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:
parent
d492694916
commit
32c203577a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=44666
@ -6,7 +6,7 @@
|
|||||||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
* 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.
|
* This driver implements a draft-mogul-pps-api-02.txt PPS source.
|
||||||
*
|
*
|
||||||
@ -16,7 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "opt_devfs.h"
|
#include "opt_devfs.h"
|
||||||
#include "opt_ntp.h"
|
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
@ -36,20 +35,11 @@
|
|||||||
static struct pps_data {
|
static struct pps_data {
|
||||||
int pps_unit;
|
int pps_unit;
|
||||||
struct ppb_device pps_dev;
|
struct ppb_device pps_dev;
|
||||||
pps_params_t ppsparam;
|
struct pps_state pps;
|
||||||
pps_info_t ppsinfo;
|
|
||||||
} *softc[NPPS];
|
} *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 int npps;
|
||||||
|
static pps_devsw_installed = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make ourselves visible as a ppbus driver
|
* Make ourselves visible as a ppbus driver
|
||||||
@ -77,6 +67,7 @@ static struct cdevsw pps_cdevsw =
|
|||||||
seltrue, nommap, nostrat, PPS_NAME,
|
seltrue, nommap, nostrat, PPS_NAME,
|
||||||
NULL, -1 };
|
NULL, -1 };
|
||||||
|
|
||||||
|
|
||||||
static struct ppb_device *
|
static struct ppb_device *
|
||||||
ppsprobe(struct ppb_data *ppb)
|
ppsprobe(struct ppb_data *ppb)
|
||||||
{
|
{
|
||||||
@ -99,12 +90,16 @@ ppsprobe(struct ppb_data *ppb)
|
|||||||
sc->pps_dev.name = ppsdriver.name;
|
sc->pps_dev.name = ppsdriver.name;
|
||||||
sc->pps_dev.intr = ppsintr;
|
sc->pps_dev.intr = ppsintr;
|
||||||
|
|
||||||
|
sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
|
||||||
|
pps_init(&sc->pps);
|
||||||
return (&sc->pps_dev);
|
return (&sc->pps_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ppsattach(struct ppb_device *dev)
|
ppsattach(struct ppb_device *dev)
|
||||||
{
|
{
|
||||||
|
dev_t devt;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Report ourselves
|
* Report ourselves
|
||||||
*/
|
*/
|
||||||
@ -116,7 +111,11 @@ ppsattach(struct ppb_device *dev)
|
|||||||
dev->id_unit, DV_CHR,
|
dev->id_unit, DV_CHR,
|
||||||
UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit);
|
UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit);
|
||||||
#endif
|
#endif
|
||||||
|
if( ! pps_devsw_installed ) {
|
||||||
|
devt = makedev(CDEV_MAJOR, 0);
|
||||||
|
cdevsw_add(&devt, &pps_cdevsw, NULL);
|
||||||
|
pps_devsw_installed = 1;
|
||||||
|
}
|
||||||
return (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)];
|
struct pps_data *sc = softc[minor(dev)];
|
||||||
|
|
||||||
sc->ppsparam.mode = 0;
|
sc->pps.ppsparam.mode = 0; /* PHK ??? */
|
||||||
|
|
||||||
ppb_wdtr(&sc->pps_dev, 0);
|
ppb_wdtr(&sc->pps_dev, 0);
|
||||||
ppb_wctr(&sc->pps_dev, 0);
|
ppb_wctr(&sc->pps_dev, 0);
|
||||||
@ -158,32 +157,17 @@ static void
|
|||||||
ppsintr(int unit)
|
ppsintr(int unit)
|
||||||
{
|
{
|
||||||
struct pps_data *sc = softc[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))
|
if (!(ppb_rstr(&sc->pps_dev) & nACK))
|
||||||
return;
|
return;
|
||||||
if (sc->ppsparam.mode & PPS_ECHOASSERT)
|
if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
|
||||||
ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED);
|
ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED);
|
||||||
if (sc->ppsparam.mode & PPS_OFFSETASSERT) {
|
pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT);
|
||||||
timespecadd(&tc, &sc->ppsparam.assert_offset);
|
if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
|
||||||
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)
|
|
||||||
ppb_wctr(&sc->pps_dev, IRQENABLE);
|
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)];
|
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)
|
|
||||||
|
@ -37,9 +37,11 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
|
* @(#)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/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/dkstat.h>
|
#include <sys/dkstat.h>
|
||||||
@ -50,6 +52,7 @@
|
|||||||
#include <sys/resourcevar.h>
|
#include <sys/resourcevar.h>
|
||||||
#include <sys/signalvar.h>
|
#include <sys/signalvar.h>
|
||||||
#include <sys/timex.h>
|
#include <sys/timex.h>
|
||||||
|
#include <sys/timepps.h>
|
||||||
#include <vm/vm.h>
|
#include <vm/vm.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include <vm/pmap.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
|
* We have eight functions for looking at the clock, four for
|
||||||
* and two for nanoseconds. For each there is fast but less precise
|
* microseconds and four for nanoseconds. For each there is fast
|
||||||
* version "get{nano|micro}time" which will return a time which is up
|
* but less precise version "get{nano|micro}[up]time" which will
|
||||||
* to 1/HZ previous to the call, whereas the raw version "{nano|micro}time"
|
* return a time which is up to 1/HZ previous to the call, whereas
|
||||||
* will return a timestamp which is as precise as possible.
|
* 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
|
void
|
||||||
@ -582,29 +588,6 @@ nanotime(struct timespec *ts)
|
|||||||
ts->tv_nsec = delta;
|
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
|
void
|
||||||
getmicrouptime(struct timeval *tvp)
|
getmicrouptime(struct timeval *tvp)
|
||||||
{
|
{
|
||||||
@ -805,8 +788,6 @@ tco_forward(int force)
|
|||||||
while (tc->tc_offset_nano >= 1000000000ULL << 32) {
|
while (tc->tc_offset_nano >= 1000000000ULL << 32) {
|
||||||
tc->tc_offset_nano -= 1000000000ULL << 32;
|
tc->tc_offset_nano -= 1000000000ULL << 32;
|
||||||
tc->tc_offset_sec++;
|
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 */
|
ntp_update_second(tc); /* XXX only needed if xntpd runs */
|
||||||
tco_setscales(tc);
|
tco_setscales(tc);
|
||||||
force++;
|
force++;
|
||||||
@ -832,24 +813,6 @@ tco_forward(int force)
|
|||||||
timecounter = tc;
|
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_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
|
||||||
|
|
||||||
SYSCTL_INT(_kern_timecounter, KERN_ARGMAX, method, CTLFLAG_RW, &tco_method, 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,
|
int
|
||||||
0, sizeof(int), sysctl_kern_timecounter_adjustment, "I", "");
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Adapted from the original sources for FreeBSD and timecounters by:
|
* 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"
|
* 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
|
* 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
|
* 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)
|
* sys/kern/kern_clock.c. Some of the comments below may be (even more)
|
||||||
* confusing and/or plain wrong in that context.
|
* 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/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/sysproto.h>
|
#include <sys/sysproto.h>
|
||||||
@ -167,7 +166,6 @@ struct ppstime {
|
|||||||
static struct ppstime pps_tf[3]; /* phase median filter */
|
static struct ppstime pps_tf[3]; /* phase median filter */
|
||||||
static struct ppstime pps_filt; /* phase offset */
|
static struct ppstime pps_filt; /* phase offset */
|
||||||
static l_fp pps_freq; /* scaled frequency offset (ns/s) */
|
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_offacc; /* offset accumulator */
|
||||||
static long pps_jitter; /* scaled time dispersion (ns) */
|
static long pps_jitter; /* scaled time dispersion (ns) */
|
||||||
static long pps_stabil; /* scaled frequency dispersion (ns/s) */
|
static long pps_stabil; /* scaled frequency dispersion (ns/s) */
|
||||||
@ -382,7 +380,7 @@ void
|
|||||||
ntp_update_second(struct timecounter *tcp)
|
ntp_update_second(struct timecounter *tcp)
|
||||||
{
|
{
|
||||||
u_int32_t *newsec;
|
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;
|
newsec = &tcp->tc_offset_sec;
|
||||||
time_maxerror += MAXFREQ / 1000;
|
time_maxerror += MAXFREQ / 1000;
|
||||||
@ -654,16 +652,17 @@ hardpps(tsp, nsec)
|
|||||||
* boundary during the last second, so correct the tick. Very
|
* boundary during the last second, so correct the tick. Very
|
||||||
* intricate.
|
* intricate.
|
||||||
*/
|
*/
|
||||||
u_nsec = nsec - pps_lastcount;
|
u_nsec = nsec;
|
||||||
pps_lastcount = nsec;
|
|
||||||
if (u_nsec > (NANOSECOND >> 1))
|
if (u_nsec > (NANOSECOND >> 1))
|
||||||
u_nsec -= NANOSECOND;
|
u_nsec -= NANOSECOND;
|
||||||
else if (u_nsec < -(NANOSECOND >> 1))
|
else if (u_nsec < -(NANOSECOND >> 1))
|
||||||
u_nsec += NANOSECOND;
|
u_nsec += NANOSECOND;
|
||||||
|
#if 0
|
||||||
if (u_nsec > (time_tick >> 1))
|
if (u_nsec > (time_tick >> 1))
|
||||||
u_nsec -= time_tick;
|
u_nsec -= time_tick;
|
||||||
else if (u_nsec < -(time_tick >> 1))
|
else if (u_nsec < -(time_tick >> 1))
|
||||||
u_nsec += time_tick;
|
u_nsec += time_tick;
|
||||||
|
#endif
|
||||||
pps_tf[0].count = pps_tf[1].count + u_nsec;
|
pps_tf[0].count = pps_tf[1].count + u_nsec;
|
||||||
if (v_nsec > MAXFREQ) {
|
if (v_nsec > MAXFREQ) {
|
||||||
return;
|
return;
|
||||||
@ -812,39 +811,3 @@ hardpps(tsp, nsec)
|
|||||||
time_freq = pps_freq;
|
time_freq = pps_freq;
|
||||||
}
|
}
|
||||||
#endif /* PPS_SYNC */
|
#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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -37,9 +37,11 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
|
* @(#)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/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/dkstat.h>
|
#include <sys/dkstat.h>
|
||||||
@ -50,6 +52,7 @@
|
|||||||
#include <sys/resourcevar.h>
|
#include <sys/resourcevar.h>
|
||||||
#include <sys/signalvar.h>
|
#include <sys/signalvar.h>
|
||||||
#include <sys/timex.h>
|
#include <sys/timex.h>
|
||||||
|
#include <sys/timepps.h>
|
||||||
#include <vm/vm.h>
|
#include <vm/vm.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include <vm/pmap.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
|
* We have eight functions for looking at the clock, four for
|
||||||
* and two for nanoseconds. For each there is fast but less precise
|
* microseconds and four for nanoseconds. For each there is fast
|
||||||
* version "get{nano|micro}time" which will return a time which is up
|
* but less precise version "get{nano|micro}[up]time" which will
|
||||||
* to 1/HZ previous to the call, whereas the raw version "{nano|micro}time"
|
* return a time which is up to 1/HZ previous to the call, whereas
|
||||||
* will return a timestamp which is as precise as possible.
|
* 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
|
void
|
||||||
@ -582,29 +588,6 @@ nanotime(struct timespec *ts)
|
|||||||
ts->tv_nsec = delta;
|
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
|
void
|
||||||
getmicrouptime(struct timeval *tvp)
|
getmicrouptime(struct timeval *tvp)
|
||||||
{
|
{
|
||||||
@ -805,8 +788,6 @@ tco_forward(int force)
|
|||||||
while (tc->tc_offset_nano >= 1000000000ULL << 32) {
|
while (tc->tc_offset_nano >= 1000000000ULL << 32) {
|
||||||
tc->tc_offset_nano -= 1000000000ULL << 32;
|
tc->tc_offset_nano -= 1000000000ULL << 32;
|
||||||
tc->tc_offset_sec++;
|
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 */
|
ntp_update_second(tc); /* XXX only needed if xntpd runs */
|
||||||
tco_setscales(tc);
|
tco_setscales(tc);
|
||||||
force++;
|
force++;
|
||||||
@ -832,24 +813,6 @@ tco_forward(int force)
|
|||||||
timecounter = tc;
|
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_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
|
||||||
|
|
||||||
SYSCTL_INT(_kern_timecounter, KERN_ARGMAX, method, CTLFLAG_RW, &tco_method, 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,
|
int
|
||||||
0, sizeof(int), sysctl_kern_timecounter_adjustment, "I", "");
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
* 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
|
* 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
|
* FPGA/RPU devices. Current Functionality is to allow you to open and
|
||||||
@ -17,6 +17,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "opt_devfs.h"
|
||||||
|
|
||||||
#include "xrpu.h"
|
#include "xrpu.h"
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
@ -24,7 +26,9 @@
|
|||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#include <sys/timepps.h>
|
#include <sys/timepps.h>
|
||||||
|
#ifdef DEFVFS
|
||||||
#include <sys/devfsext.h>
|
#include <sys/devfsext.h>
|
||||||
|
#endif
|
||||||
#include <sys/xrpuio.h>
|
#include <sys/xrpuio.h>
|
||||||
#include <pci/pcireg.h>
|
#include <pci/pcireg.h>
|
||||||
#include <pci/pcivar.h>
|
#include <pci/pcivar.h>
|
||||||
@ -64,13 +68,8 @@ static struct softc {
|
|||||||
u_int *virbase62;
|
u_int *virbase62;
|
||||||
struct timecounter tc;
|
struct timecounter tc;
|
||||||
u_int *trigger, *latch, dummy;
|
u_int *trigger, *latch, dummy;
|
||||||
struct {
|
struct pps_state pps[XRPU_MAX_PPS];
|
||||||
pps_params_t params;
|
u_int *assert[XRPU_MAX_PPS], *clear[XRPU_MAX_PPS];
|
||||||
pps_info_t info;
|
|
||||||
int cap;
|
|
||||||
u_int *assert, last_assert;
|
|
||||||
u_int *clear, last_clear;
|
|
||||||
} pps[XRPU_MAX_PPS];
|
|
||||||
} *softc[NXRPU];
|
} *softc[NXRPU];
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
@ -90,45 +89,21 @@ xrpu_poll_pps(struct timecounter *tc)
|
|||||||
unsigned count1, ppscount;
|
unsigned count1, ppscount;
|
||||||
|
|
||||||
for (i = 0; i < XRPU_MAX_PPS; i++) {
|
for (i = 0; i < XRPU_MAX_PPS; i++) {
|
||||||
if (sc->pps[i].assert) {
|
if (sc->assert[i]) {
|
||||||
ppscount = *(sc->pps[i].assert) & tc->tc_counter_mask;
|
ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
|
||||||
do {
|
do {
|
||||||
count1 = ppscount;
|
count1 = ppscount;
|
||||||
ppscount = *(sc->pps[i].assert) & tc->tc_counter_mask;
|
ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
|
||||||
} while (ppscount != count1);
|
} while (ppscount != count1);
|
||||||
if (ppscount != sc->pps[i].last_assert) {
|
pps_event(&sc->pps[i], &sc->tc, ppscount, PPS_CAPTUREASSERT);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sc->pps[i].clear) {
|
if (sc->clear[i]) {
|
||||||
ppscount = *(sc->pps[i].clear) & tc->tc_counter_mask;
|
ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
|
||||||
do {
|
do {
|
||||||
count1 = ppscount;
|
count1 = ppscount;
|
||||||
ppscount = *(sc->pps[i].clear) & tc->tc_counter_mask;
|
ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
|
||||||
} while (ppscount != count1);
|
} while (ppscount != count1);
|
||||||
if (ppscount != sc->pps[i].last_clear) {
|
pps_event(&sc->pps[i], &sc->tc, ppscount, PPS_CAPTURECLEAR);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,10 +139,7 @@ xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *pr)
|
|||||||
i = dev2pps(dev);
|
i = dev2pps(dev);
|
||||||
if (i < 0 || i >= XRPU_MAX_PPS)
|
if (i < 0 || i >= XRPU_MAX_PPS)
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
if (!sc->pps[i].cap)
|
error = pps_ioctl(cmd, arg, &sc->pps[i]);
|
||||||
return ENODEV;
|
|
||||||
error = std_pps_ioctl(cmd, arg, &sc->pps[i].params,
|
|
||||||
&sc->pps[i].info, sc->pps[i].cap);
|
|
||||||
return (error);
|
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
|
if (xt->xt_pps[i].xt_addr_assert == 0
|
||||||
&& xt->xt_pps[i].xt_addr_clear == 0)
|
&& xt->xt_pps[i].xt_addr_clear == 0)
|
||||||
continue;
|
continue;
|
||||||
devfs_add_devswf(&xrpudevsw, (i+1)<<16, DV_CHR, UID_ROOT, GID_WHEEL, 0600,
|
#ifdef DEVFS
|
||||||
"xpps%d", i);
|
devfs_add_devswf(&xrpudevsw, (i+1)<<16, DV_CHR, UID_ROOT, GID_WHEEL,
|
||||||
/* DEVFS */
|
0600, "xpps%d", i);
|
||||||
|
#endif
|
||||||
|
sc->pps[i].ppscap = 0;
|
||||||
if (xt->xt_pps[i].xt_addr_assert) {
|
if (xt->xt_pps[i].xt_addr_assert) {
|
||||||
sc->pps[i].assert = sc->virbase62 + xt->xt_pps[i].xt_addr_assert;
|
sc->assert[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_assert;
|
||||||
sc->pps[i].cap |= PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
|
sc->pps[i].ppscap |= PPS_CAPTUREASSERT;
|
||||||
}
|
}
|
||||||
if (xt->xt_pps[i].xt_addr_clear) {
|
if (xt->xt_pps[i].xt_addr_clear) {
|
||||||
sc->pps[i].clear = sc->virbase62 + xt->xt_pps[i].xt_addr_clear;
|
sc->clear[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_clear;
|
||||||
sc->pps[i].cap |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
|
sc->pps[i].ppscap |= PPS_CAPTURECLEAR;
|
||||||
}
|
}
|
||||||
|
pps_init(&sc->pps[i]);
|
||||||
}
|
}
|
||||||
sc->mode = TIMECOUNTER;
|
sc->mode = TIMECOUNTER;
|
||||||
init_timecounter(&sc->tc);
|
init_timecounter(&sc->tc);
|
||||||
@ -266,6 +241,8 @@ xrpu_attach (pcici_t tag, int unit)
|
|||||||
if (!unit)
|
if (!unit)
|
||||||
cdevsw_add(&cdev, &xrpudevsw, NULL);
|
cdevsw_add(&cdev, &xrpudevsw, NULL);
|
||||||
|
|
||||||
|
#ifdef DEVFS
|
||||||
devfs_add_devswf(&xrpudevsw, 0, DV_CHR, UID_ROOT, GID_WHEEL, 0600,
|
devfs_add_devswf(&xrpudevsw, 0, DV_CHR, UID_ROOT, GID_WHEEL, 0600,
|
||||||
"xrpu%d", unit);
|
"xrpu%d", unit);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)systm.h 8.7 (Berkeley) 3/29/95
|
* @(#)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_
|
#ifndef _SYS_SYSTM_H_
|
||||||
@ -160,8 +160,6 @@ void startprofclock __P((struct proc *));
|
|||||||
void stopprofclock __P((struct proc *));
|
void stopprofclock __P((struct proc *));
|
||||||
void setstatclockrate __P((int hzrate));
|
void setstatclockrate __P((int hzrate));
|
||||||
|
|
||||||
void hardpps __P((struct timeval *tvp, long usec));
|
|
||||||
|
|
||||||
char *getenv __P((char *name));
|
char *getenv __P((char *name));
|
||||||
int getenv_int __P((char *name, int *data));
|
int getenv_int __P((char *name, int *data));
|
||||||
extern char *kern_envp;
|
extern char *kern_envp;
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)time.h 8.5 (Berkeley) 5/4/95
|
* @(#)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_
|
#ifndef _SYS_TIME_H_
|
||||||
@ -277,7 +277,6 @@ void microtime __P((struct timeval *tv));
|
|||||||
void nanouptime __P((struct timespec *ts));
|
void nanouptime __P((struct timespec *ts));
|
||||||
void nanotime __P((struct timespec *ts));
|
void nanotime __P((struct timespec *ts));
|
||||||
void set_timecounter __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 timevaladd __P((struct timeval *, struct timeval *));
|
||||||
void timevalsub __P((struct timeval *, struct timeval *));
|
void timevalsub __P((struct timeval *, struct timeval *));
|
||||||
int tvtohz __P((struct timeval *));
|
int tvtohz __P((struct timeval *));
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
* 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"
|
* The is a FreeBSD protype version of the "draft-mogul-pps-api-02.txt"
|
||||||
* specification for Pulse Per Second timing interfaces.
|
* 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)
|
#define PPS_IOC_WAIT _IOWR('1', 6, struct pps_wait_args)
|
||||||
|
|
||||||
#ifdef KERNEL
|
#ifdef KERNEL
|
||||||
int std_pps_ioctl __P((u_long cmd, caddr_t data, pps_params_t *pp,
|
struct pps_state {
|
||||||
pps_info_t *pi, int ppscap));
|
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_ */
|
#endif /* _SYS_TIMEPPS_H_ */
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* @(#)time.h 8.5 (Berkeley) 5/4/95
|
* @(#)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_
|
#ifndef _SYS_TIME_H_
|
||||||
@ -277,7 +277,6 @@ void microtime __P((struct timeval *tv));
|
|||||||
void nanouptime __P((struct timespec *ts));
|
void nanouptime __P((struct timespec *ts));
|
||||||
void nanotime __P((struct timespec *ts));
|
void nanotime __P((struct timespec *ts));
|
||||||
void set_timecounter __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 timevaladd __P((struct timeval *, struct timeval *));
|
||||||
void timevalsub __P((struct timeval *, struct timeval *));
|
void timevalsub __P((struct timeval *, struct timeval *));
|
||||||
int tvtohz __P((struct timeval *));
|
int tvtohz __P((struct timeval *));
|
||||||
|
@ -59,14 +59,11 @@
|
|||||||
*
|
*
|
||||||
* SYNOPSIS
|
* SYNOPSIS
|
||||||
* #include <sys/timex.h>
|
* #include <sys/timex.h>
|
||||||
* #include <sys/syscall.h>
|
|
||||||
*
|
*
|
||||||
* int syscall(SYS_ntp_gettime, tptr);
|
* int ntp_gettime(struct ntptimeval *ntv);
|
||||||
* int SYS_ntp_gettime;
|
|
||||||
* struct ntptimeval *tptr;
|
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* 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
|
* but may be in either microsecond (seconds and microseconds) or
|
||||||
* nanosecond (seconds and nanoseconds) format. The particular
|
* nanosecond (seconds and nanoseconds) format. The particular
|
||||||
* format in use is determined by the STA_NANO bit of the status
|
* format in use is determined by the STA_NANO bit of the status
|
||||||
@ -80,6 +77,7 @@
|
|||||||
* #include <sys/syscall.h>
|
* #include <sys/syscall.h>
|
||||||
*
|
*
|
||||||
* int syscall(SYS_ntp_adjtime, tptr);
|
* int syscall(SYS_ntp_adjtime, tptr);
|
||||||
|
* int SYS_ntp_adjtime;
|
||||||
* struct timex *tptr;
|
* struct timex *tptr;
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
@ -89,7 +87,7 @@
|
|||||||
* further information.
|
* further information.
|
||||||
*/
|
*/
|
||||||
#ifndef _SYS_TIMEX_H_
|
#ifndef _SYS_TIMEX_H_
|
||||||
#define _SYS_TIMEX_H_ 1
|
#define _SYS_TIMEX_H_
|
||||||
|
|
||||||
#ifndef MSDOS /* Microsoft specific */
|
#ifndef MSDOS /* Microsoft specific */
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
@ -171,7 +169,7 @@
|
|||||||
* nanoseconds if not.
|
* nanoseconds if not.
|
||||||
*/
|
*/
|
||||||
struct ntptimeval {
|
struct ntptimeval {
|
||||||
struct timespec time; /* current time (ns) (ro) */
|
struct timespec time; /* current time (ns/us) (ro) */
|
||||||
long maxerror; /* maximum error (us) (ro) */
|
long maxerror; /* maximum error (us) (ro) */
|
||||||
long esterror; /* estimated error (us) (ro) */
|
long esterror; /* estimated error (us) (ro) */
|
||||||
int time_state; /* time status */
|
int time_state; /* time status */
|
||||||
@ -214,16 +212,17 @@ struct timex {
|
|||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
|
|
||||||
#ifdef KERNEL
|
#ifdef KERNEL
|
||||||
void ntp_update_second __P((struct timecounter *tc));
|
struct timecounter;
|
||||||
#else
|
void ntp_update_second __P((struct timecounter *tc));
|
||||||
|
#else /* !KERNEL */
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
extern int ntp_gettime __P((struct ntptimeval *));
|
int ntp_adjtime __P((struct timex *));
|
||||||
extern int ntp_adjtime __P((struct timex *));
|
int ntp_gettime __P((struct ntptimeval *));
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
#endif /* KERNEL */
|
||||||
#endif /* not KERNEL */
|
|
||||||
|
|
||||||
#endif /* __FreeBSD__ */
|
#endif /* __FreeBSD__ */
|
||||||
#endif /* _SYS_TIMEX_H_ */
|
|
||||||
|
#endif /* !_SYS_TIMEX_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user