diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 66e26d01e73..e5db8d90024 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -1365,6 +1365,9 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) { pps_params_t *app; struct pps_fetch_args *fapi; +#ifdef FFCLOCK + struct pps_fetch_ffc_args *fapi_ffc; +#endif #ifdef PPS_SYNC struct pps_kcbind_args *kapi; #endif @@ -1379,6 +1382,11 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) app = (pps_params_t *)data; if (app->mode & ~pps->ppscap) return (EINVAL); +#ifdef FFCLOCK + /* Ensure only a single clock is selected for ffc timestamp. */ + if ((app->mode & PPS_TSCLK_MASK) == PPS_TSCLK_MASK) + return (EINVAL); +#endif pps->ppsparam = *app; return (0); case PPS_IOC_GETPARAMS: @@ -1398,6 +1406,31 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) pps->ppsinfo.current_mode = pps->ppsparam.mode; fapi->pps_info_buf = pps->ppsinfo; return (0); +#ifdef FFCLOCK + case PPS_IOC_FETCH_FFCOUNTER: + fapi_ffc = (struct pps_fetch_ffc_args *)data; + if (fapi_ffc->tsformat && fapi_ffc->tsformat != + PPS_TSFMT_TSPEC) + return (EINVAL); + if (fapi_ffc->timeout.tv_sec || fapi_ffc->timeout.tv_nsec) + return (EOPNOTSUPP); + pps->ppsinfo_ffc.current_mode = pps->ppsparam.mode; + fapi_ffc->pps_info_buf_ffc = pps->ppsinfo_ffc; + /* Overwrite timestamps if feedback clock selected. */ + switch (pps->ppsparam.mode & PPS_TSCLK_MASK) { + case PPS_TSCLK_FBCK: + fapi_ffc->pps_info_buf_ffc.assert_timestamp = + pps->ppsinfo.assert_timestamp; + fapi_ffc->pps_info_buf_ffc.clear_timestamp = + pps->ppsinfo.clear_timestamp; + break; + case PPS_TSCLK_FFWD: + break; + default: + break; + } + return (0); +#endif /* FFCLOCK */ case PPS_IOC_KCBIND: #ifdef PPS_SYNC kapi = (struct pps_kcbind_args *)data; @@ -1426,6 +1459,9 @@ pps_init(struct pps_state *pps) pps->ppscap |= PPS_OFFSETASSERT; if (pps->ppscap & PPS_CAPTURECLEAR) pps->ppscap |= PPS_OFFSETCLEAR; +#ifdef FFCLOCK + pps->ppscap |= PPS_TSCLK_MASK; +#endif } void @@ -1437,6 +1473,9 @@ pps_capture(struct pps_state *pps) th = timehands; pps->capgen = th->th_generation; pps->capth = th; +#ifdef FFCLOCK + pps->capffth = fftimehands; +#endif pps->capcount = th->th_counter->tc_get_timecount(th->th_counter); if (pps->capgen != th->th_generation) pps->capgen = 0; @@ -1450,6 +1489,11 @@ pps_event(struct pps_state *pps, int event) u_int tcount, *pcount; int foff, fhard; pps_seq_t *pseq; +#ifdef FFCLOCK + struct timespec *tsp_ffc; + pps_seq_t *pseq_ffc; + ffcounter *ffcount; +#endif KASSERT(pps != NULL, ("NULL pps pointer in pps_event")); /* If the timecounter was wound up underneath us, bail out. */ @@ -1464,6 +1508,11 @@ pps_event(struct pps_state *pps, int event) fhard = pps->kcmode & PPS_CAPTUREASSERT; pcount = &pps->ppscount[0]; pseq = &pps->ppsinfo.assert_sequence; +#ifdef FFCLOCK + ffcount = &pps->ppsinfo_ffc.assert_ffcount; + tsp_ffc = &pps->ppsinfo_ffc.assert_timestamp; + pseq_ffc = &pps->ppsinfo_ffc.assert_sequence; +#endif } else { tsp = &pps->ppsinfo.clear_timestamp; osp = &pps->ppsparam.clear_offset; @@ -1471,6 +1520,11 @@ pps_event(struct pps_state *pps, int event) fhard = pps->kcmode & PPS_CAPTURECLEAR; pcount = &pps->ppscount[1]; pseq = &pps->ppsinfo.clear_sequence; +#ifdef FFCLOCK + ffcount = &pps->ppsinfo_ffc.clear_ffcount; + tsp_ffc = &pps->ppsinfo_ffc.clear_timestamp; + pseq_ffc = &pps->ppsinfo_ffc.clear_sequence; +#endif } /* @@ -1507,6 +1561,17 @@ pps_event(struct pps_state *pps, int event) tsp->tv_sec -= 1; } } + +#ifdef FFCLOCK + *ffcount = pps->capffth->tick_ffcount + tcount; + bt = pps->capffth->tick_time; + ffclock_convert_delta(tcount, pps->capffth->cest.period, &bt); + bintime_add(&bt, &pps->capffth->tick_time); + bintime2timespec(&bt, &ts); + (*pseq_ffc)++; + *tsp_ffc = ts; +#endif + #ifdef PPS_SYNC if (fhard) { uint64_t scale; diff --git a/sys/sys/timepps.h b/sys/sys/timepps.h index cde9396145f..8083f33a160 100644 --- a/sys/sys/timepps.h +++ b/sys/sys/timepps.h @@ -6,6 +6,12 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Julien Ridoux at the University + * of Melbourne under sponsorship from the FreeBSD Foundation. + * * $FreeBSD$ * * The is a FreeBSD version of the RFC 2783 API for Pulse Per Second @@ -15,6 +21,7 @@ #ifndef _SYS_TIMEPPS_H_ #define _SYS_TIMEPPS_H_ +#include #include #include @@ -43,6 +50,16 @@ typedef struct { int current_mode; /* current mode bits */ } pps_info_t; +typedef struct { + pps_seq_t assert_sequence; /* assert event seq # */ + pps_seq_t clear_sequence; /* clear event seq # */ + pps_timeu_t assert_tu; + pps_timeu_t clear_tu; + ffcounter assert_ffcount; /* ffcounter on assert event */ + ffcounter clear_ffcount; /* ffcounter on clear event */ + int current_mode; /* current mode bits */ +} pps_info_ffc_t; + #define assert_timestamp assert_tu.tspec #define clear_timestamp clear_tu.tspec @@ -79,6 +96,10 @@ typedef struct { #define PPS_TSFMT_TSPEC 0x1000 #define PPS_TSFMT_NTPFP 0x2000 +#define PPS_TSCLK_FBCK 0x10000 +#define PPS_TSCLK_FFWD 0x20000 +#define PPS_TSCLK_MASK 0x30000 + #define PPS_KC_HARDPPS 0 #define PPS_KC_HARDPPS_PLL 1 #define PPS_KC_HARDPPS_FLL 2 @@ -89,6 +110,12 @@ struct pps_fetch_args { struct timespec timeout; }; +struct pps_fetch_ffc_args { + int tsformat; + pps_info_ffc_t pps_info_buf_ffc; + struct timespec timeout; +}; + struct pps_kcbind_args { int kernel_consumer; int edge; @@ -102,18 +129,21 @@ struct pps_kcbind_args { #define PPS_IOC_GETCAP _IOR('1', 5, int) #define PPS_IOC_FETCH _IOWR('1', 6, struct pps_fetch_args) #define PPS_IOC_KCBIND _IOW('1', 7, struct pps_kcbind_args) +#define PPS_IOC_FETCH_FFCOUNTER _IOWR('1', 8, struct pps_fetch_ffc_args) #ifdef _KERNEL struct pps_state { /* Capture information. */ struct timehands *capth; + struct fftimehands *capffth; unsigned capgen; unsigned capcount; /* State information. */ pps_params_t ppsparam; pps_info_t ppsinfo; + pps_info_ffc_t ppsinfo_ffc; int kcmode; int ppscap; struct timecounter *ppstc; @@ -183,6 +213,25 @@ time_pps_fetch(pps_handle_t handle, const int tsformat, return (error); } +static __inline int +time_pps_fetch_ffc(pps_handle_t handle, const int tsformat, + pps_info_ffc_t *ppsinfobuf, const struct timespec *timeout) +{ + struct pps_fetch_ffc_args arg; + int error; + + arg.tsformat = tsformat; + if (timeout == NULL) { + arg.timeout.tv_sec = -1; + arg.timeout.tv_nsec = -1; + } else { + arg.timeout = *timeout; + } + error = ioctl(handle, PPS_IOC_FETCH_FFCOUNTER, &arg); + *ppsinfobuf = arg.pps_info_buf_ffc; + return (error); +} + static __inline int time_pps_kcbind(pps_handle_t handle, const int kernel_consumer, const int edge, const int tsformat)