summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_tc.c
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2013-02-15 18:30:32 +0000
committerian <ian@FreeBSD.org>2013-02-15 18:30:32 +0000
commit683ffef109f29f69c994debd2602613353173dda (patch)
tree50ee0e49c67880fc72cb4b5025bff6db0c054a9a /sys/kern/kern_tc.c
parentcb7ef0d72fdbd149e546d7ad7f4d7e6a2b5caebf (diff)
downloadFreeBSD-src-683ffef109f29f69c994debd2602613353173dda.zip
FreeBSD-src-683ffef109f29f69c994debd2602613353173dda.tar.gz
Add PPS_CANWAIT support for time_pps_fetch(). This adds support for all three
blocking modes described in section 3.4.3 of RFC 2783, allowing the caller to retrieve the most recent values without blocking, to block for a specified time, or to block forever. Reviewed by: discussion on hackers@
Diffstat (limited to 'sys/kern/kern_tc.c')
-rw-r--r--sys/kern/kern_tc.c57
1 files changed, 49 insertions, 8 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
index 2ffa2f9..6e1f486 100644
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -1446,6 +1446,50 @@ SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD,
* RFC 2783 PPS-API implementation.
*/
+static int
+pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps)
+{
+ int err, timo;
+ pps_seq_t aseq, cseq;
+ struct timeval tv;
+
+ if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC)
+ return (EINVAL);
+
+ /*
+ * If no timeout is requested, immediately return whatever values were
+ * most recently captured. If timeout seconds is -1, that's a request
+ * to block without a timeout. WITNESS won't let us sleep forever
+ * without a lock (we really don't need a lock), so just repeatedly
+ * sleep a long time.
+ */
+ if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) {
+ if (fapi->timeout.tv_sec == -1)
+ timo = 0x7fffffff;
+ else {
+ tv.tv_sec = fapi->timeout.tv_sec;
+ tv.tv_usec = fapi->timeout.tv_nsec / 1000;
+ timo = tvtohz(&tv);
+ }
+ aseq = pps->ppsinfo.assert_sequence;
+ cseq = pps->ppsinfo.clear_sequence;
+ while (aseq == pps->ppsinfo.assert_sequence &&
+ cseq == pps->ppsinfo.clear_sequence) {
+ err = tsleep(pps, PCATCH, "ppsfch", timo);
+ if (err == EWOULDBLOCK && fapi->timeout.tv_sec == -1) {
+ continue;
+ } else if (err != 0) {
+ return (err);
+ }
+ }
+ }
+
+ pps->ppsinfo.current_mode = pps->ppsparam.mode;
+ fapi->pps_info_buf = pps->ppsinfo;
+
+ return (0);
+}
+
int
pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
{
@@ -1485,13 +1529,7 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
return (0);
case PPS_IOC_FETCH:
fapi = (struct pps_fetch_args *)data;
- if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC)
- return (EINVAL);
- if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec)
- return (EOPNOTSUPP);
- pps->ppsinfo.current_mode = pps->ppsparam.mode;
- fapi->pps_info_buf = pps->ppsinfo;
- return (0);
+ return (pps_fetch(fapi, pps));
#ifdef FFCLOCK
case PPS_IOC_FETCH_FFCOUNTER:
fapi_ffc = (struct pps_fetch_ffc_args *)data;
@@ -1540,7 +1578,7 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
void
pps_init(struct pps_state *pps)
{
- pps->ppscap |= PPS_TSFMT_TSPEC;
+ pps->ppscap |= PPS_TSFMT_TSPEC | PPS_CANWAIT;
if (pps->ppscap & PPS_CAPTUREASSERT)
pps->ppscap |= PPS_OFFSETASSERT;
if (pps->ppscap & PPS_CAPTURECLEAR)
@@ -1680,6 +1718,9 @@ pps_event(struct pps_state *pps, int event)
hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);
}
#endif
+
+ /* Wakeup anyone sleeping in pps_fetch(). */
+ wakeup(pps);
}
/*
OpenPOWER on IntegriCloud