Index: conf/GENERIC =================================================================== RCS file: /cvs/src/sys/conf/GENERIC,v retrieving revision 1.273 diff -u -p -r1.273 GENERIC --- conf/GENERIC 30 Sep 2020 14:51:17 -0000 1.273 +++ conf/GENERIC 21 Dec 2020 05:13:41 -0000 @@ -82,6 +82,7 @@ pseudo-device msts 1 # MSTS line discipl pseudo-device endrun 1 # EndRun line discipline pseudo-device vnd 4 # vnode disk devices pseudo-device ksyms 1 # kernel symbols device +pseudo-device kstat # kernel statistics #pseudo-device dt # Dynamic Tracer # clonable devices Index: dev/pci/if_mcx.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_mcx.c,v retrieving revision 1.80 diff -u -p -r1.80 if_mcx.c --- dev/pci/if_mcx.c 17 Dec 2020 04:15:03 -0000 1.80 +++ dev/pci/if_mcx.c 21 Dec 2020 05:13:41 -0000 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -2248,11 +2249,13 @@ struct mcx_cq { }; struct mcx_calibration { - uint64_t c_timestamp; /* previous mcx chip time */ - uint64_t c_uptime; /* previous kernel nanouptime */ + struct timecycle c_timecycle; +#define c_ubase c_timecycle.tcyc_cycles uint64_t c_tbase; /* mcx chip time */ - uint64_t c_ubase; /* kernel nanouptime */ - uint64_t c_ratio; + uint64_t c_timestamp; /* previous mcx chip time */ + uint64_t c_uptime; /* previous kernel cycles */ + uint64_t c_tdiff; + uint64_t c_udiff; }; #define MCX_CALIBRATE_FIRST 2 @@ -2467,7 +2470,11 @@ struct mcx_softc { struct kstat *sc_kstat_rfc3635; unsigned int sc_kstat_mtmp_count; struct kstat **sc_kstat_mtmp; + struct kstat *sc_kstat_calibrate; #endif + + unsigned int sc_timecounter_reads; + struct timecounter sc_timecounter; }; #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) @@ -2478,6 +2485,8 @@ static void mcx_attach(struct device *, static void mcx_kstat_attach(struct mcx_softc *); #endif +static void mcx_timecounter_attach(struct mcx_softc *); + static int mcx_version(struct mcx_softc *); static int mcx_init_wait(struct mcx_softc *); static int mcx_enable_hca(struct mcx_softc *); @@ -2551,7 +2560,8 @@ static void mcx_cmdq_mbox_dump(struct mc static void mcx_refill(void *); static int mcx_process_rx(struct mcx_softc *, struct mcx_rx *, struct mcx_cq_entry *, struct mbuf_list *, - const struct mcx_calibration *); + const struct mcx_calibration *, const struct timecycle *, + uint64_t); static void mcx_process_txeof(struct mcx_softc *, struct mcx_tx *, struct mcx_cq_entry *, int *); static void mcx_process_cq(struct mcx_softc *, struct mcx_queues *, @@ -2947,6 +2957,7 @@ mcx_attach(struct device *parent, struct #if NKSTAT > 0 mcx_kstat_attach(sc); #endif + mcx_timecounter_attach(sc); return; teardown: @@ -6576,16 +6587,6 @@ mcx_process_txeof(struct mcx_softc *sc, ms->ms_m = NULL; } -static uint64_t -mcx_uptime(void) -{ - struct timespec ts; - - nanouptime(&ts); - - return ((uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec); -} - static void mcx_calibrate_first(struct mcx_softc *sc) { @@ -6594,23 +6595,23 @@ mcx_calibrate_first(struct mcx_softc *sc sc->sc_calibration_gen = 0; - s = splhigh(); /* crit_enter? */ - c->c_ubase = mcx_uptime(); + s = splhigh(); + timecycle(&c->c_timecycle); c->c_tbase = mcx_timer(sc); splx(s); - c->c_ratio = 0; + c->c_tdiff = 0; timeout_add_sec(&sc->sc_calibrate, MCX_CALIBRATE_FIRST); } -#define MCX_TIMESTAMP_SHIFT 24 +#define MCX_TIMESTAMP_SHIFT 10 static void mcx_calibrate(void *arg) { struct mcx_softc *sc = arg; - struct mcx_calibration *nc, *pc; - uint64_t udiff, tdiff; + struct mcx_calibration *nc; + const struct mcx_calibration *pc; unsigned int gen; int s; @@ -6627,24 +6628,18 @@ mcx_calibrate(void *arg) nc->c_uptime = pc->c_ubase; nc->c_timestamp = pc->c_tbase; - s = splhigh(); /* crit_enter? */ - nc->c_ubase = mcx_uptime(); + s = splhigh(); /* XXX critical section */ + timecycle(&nc->c_timecycle); nc->c_tbase = mcx_timer(sc); splx(s); - udiff = nc->c_ubase - nc->c_uptime; - tdiff = nc->c_tbase - nc->c_timestamp; - - /* - * udiff is the wall clock time between calibration ticks, - * which should be 32 seconds or 32 billion nanoseconds. if - * we squint, 1 billion nanoseconds is kind of like a 32 bit - * number, so 32 billion should still have a lot of high bits - * spare. we use this space by shifting the nanoseconds up - * 24 bits so we have a nice big number to divide by the - * number of mcx timer ticks. - */ - nc->c_ratio = (udiff << MCX_TIMESTAMP_SHIFT) / tdiff; + if (pc->c_timecycle.tcyc_version == nc->c_timecycle.tcyc_version) { + nc->c_udiff = (nc->c_ubase - nc->c_uptime) >> + MCX_TIMESTAMP_SHIFT; + nc->c_tdiff = (nc->c_tbase - nc->c_timestamp) >> + MCX_TIMESTAMP_SHIFT; + } else + nc->c_tdiff = 0; membar_producer(); sc->sc_calibration_gen = gen; @@ -6653,7 +6648,8 @@ mcx_calibrate(void *arg) static int mcx_process_rx(struct mcx_softc *sc, struct mcx_rx *rx, struct mcx_cq_entry *cqe, struct mbuf_list *ml, - const struct mcx_calibration *c) + const struct mcx_calibration *c, const struct timecycle *tcyc, + uint64_t nsec) { struct mcx_slot *ms; struct mbuf *m; @@ -6691,14 +6687,28 @@ mcx_process_rx(struct mcx_softc *sc, str } #endif - if (ISSET(sc->sc_ac.ac_if.if_flags, IFF_LINK0) && c->c_ratio) { - uint64_t t = bemtoh64(&cqe->cq_timestamp); + if (c != NULL) { + int64_t delta; + uint64_t t; + + /* convert mcx timestamp to a timecounter value */ + t = bemtoh64(&cqe->cq_timestamp); t -= c->c_timestamp; - t *= c->c_ratio; - t >>= MCX_TIMESTAMP_SHIFT; + t *= c->c_udiff; + t /= c->c_tdiff; t += c->c_uptime; - m->m_pkthdr.ph_timestamp = t; + /* + * calculate a delta between the mcx derived + * timecounter and the one used for the timehand. + */ + delta = t - tcyc->tcyc_cycles; + delta *= tcyc->tcyc_scale; + + /* convert frac to nsec and apply */ + nsec += (1000000000LL * (delta >> 32)) >> 32; + + m->m_pkthdr.ph_timestamp = nsec; SET(m->m_pkthdr.csum_flags, M_TIMESTAMP); } @@ -6747,21 +6757,43 @@ mcx_arm_cq(struct mcx_softc *sc, struct BUS_SPACE_BARRIER_WRITE); } +static inline const struct mcx_calibration * +mcx_get_calibration(struct mcx_softc *sc, struct timecycle *tcyc) +{ + const struct mcx_calibration *c; + unsigned int gen; + + gen = sc->sc_calibration_gen; + membar_consumer(); + c = &sc->sc_calibration[gen % nitems(sc->sc_calibration)]; + if (c->c_tdiff == 0) + return (NULL); + + gettimecycle(tcyc); + if (tcyc->tcyc_version != c->c_timecycle.tcyc_version) + return (NULL); + + return (c); +} + void mcx_process_cq(struct mcx_softc *sc, struct mcx_queues *q, struct mcx_cq *cq) { struct mcx_rx *rx = &q->q_rx; struct mcx_tx *tx = &q->q_tx; const struct mcx_calibration *c; - unsigned int gen; + struct timecycle tcyc; + uint64_t nsec = 0; struct mcx_cq_entry *cqe; uint8_t *cqp; struct mbuf_list ml = MBUF_LIST_INITIALIZER(); int rxfree, txfree; - gen = sc->sc_calibration_gen; - membar_consumer(); - c = &sc->sc_calibration[gen % nitems(sc->sc_calibration)]; + c = mcx_get_calibration(sc, &tcyc); + if (c != NULL) { + nsec = tcyc.tcyc_offset.sec * 1000000000LL; + nsec += (1000000000LL * (tcyc.tcyc_offset.frac >> 32)) >> 32; + } rxfree = 0; txfree = 0; @@ -6773,7 +6805,8 @@ mcx_process_cq(struct mcx_softc *sc, str mcx_process_txeof(sc, tx, cqe, &txfree); break; case MCX_CQ_ENTRY_OPCODE_SEND: - rxfree += mcx_process_rx(sc, rx, cqe, &ml, c); + rxfree += mcx_process_rx(sc, rx, cqe, &ml, + c, &tcyc, nsec); break; case MCX_CQ_ENTRY_OPCODE_REQ_ERR: case MCX_CQ_ENTRY_OPCODE_SEND_ERR: @@ -8183,6 +8216,169 @@ mcx_kstat_attach_ppcnt(struct mcx_softc return (ks); } +struct mcx_kstat_calibrate { + struct kstat_kv kc_mhz; + struct kstat_kv kc_khz; + struct kstat_kv kc_ubase; + struct kstat_kv kc_tbase; + struct kstat_kv kc_uptime; + struct kstat_kv kc_timestamp; + struct kstat_kv kc_udiff; + struct kstat_kv kc_tdiff; + struct kstat_kv kc_delta; + + struct kstat_kv kc_timer; + struct kstat_kv kc_tc; + struct kstat_kv kc_cc; + struct kstat_kv kc_cc_tc; + struct kstat_kv kc_know; + struct kstat_kv kc_tnow; + struct kstat_kv kc_diff; + struct kstat_kv kc_maths; + + struct kstat_kv kc_tc_reads; +}; + +static int +mcx_kstat_calibrate_read(struct kstat *ks) +{ + struct mcx_softc *sc = ks->ks_softc; + struct mcx_kstat_calibrate *kc = ks->ks_data; + const struct mcx_calibration *c; + struct timecycle tc; + struct timecycle tcyc; + unsigned int gen; + uint64_t t, u; + int s; + + gen = sc->sc_calibration_gen; + membar_consumer(); + c = &sc->sc_calibration[gen % nitems(sc->sc_calibration)]; + + s = splhigh(); /* crit_enter */ + timecycle(&tc); + t = mcx_timer(sc); + + nanouptime(&ks->ks_updated); + splx(s); + + kstat_kv_u64(&kc->kc_ubase) = c->c_ubase; + kstat_kv_u64(&kc->kc_tbase) = c->c_tbase; + kstat_kv_u64(&kc->kc_uptime) = c->c_uptime; + kstat_kv_u64(&kc->kc_timestamp) = c->c_timestamp; + kstat_kv_u64(&kc->kc_udiff) = c->c_udiff; + kstat_kv_u64(&kc->kc_tdiff) = c->c_tdiff; + + kstat_kv_u64(&kc->kc_timer) = t; + + kstat_kv_timespec(&kc->kc_know) = ks->ks_updated; + u = TIMESPEC_TO_NSEC(&ks->ks_updated); + + /* + * get the current wall clock time adjustments without + * reading the timecounter. + */ + gettimecycle(&tcyc); + + /* + * is mcx using the same timecounter as the kernel, and is + * it calibrated? + */ + if (tcyc.tcyc_version == c->c_timecycle.tcyc_version && c->c_tdiff) { + int64_t diff; + uint64_t nsec; + + /* convert bintime to nsec */ + nsec = tcyc.tcyc_offset.sec * 1000000000LL; + nsec += (1000000000LL * (tcyc.tcyc_offset.frac >> 32)) >> 32; + + /* calculate timecounter according to mcx timestamp */ + t -= c->c_timestamp; + t *= c->c_udiff; + t /= c->c_tdiff; + t += c->c_uptime; + + kstat_kv_u64(&kc->kc_cc) = t; + kstat_kv_u64(&kc->kc_tc) = tc.tcyc_cycles; + kstat_kv_u64(&kc->kc_cc_tc) = t - tc.tcyc_cycles; + + /* + * calculate a delta between the mcx derived + * timecounter and the one used for the timehand. + */ + diff = t - tcyc.tcyc_cycles; + kstat_kv_s64(&kc->kc_delta) = diff; + + /* + * apply the wall time adjustment. + */ + diff *= tcyc.tcyc_scale; + + /* convert frac to nsec and apply */ + nsec += (1000000000LL * (diff >> 32)) >> 32; + + NSEC_TO_TIMESPEC(nsec, &kstat_kv_timespec(&kc->kc_tnow)); + kstat_kv_s64(&kc->kc_diff) = u - nsec; + kstat_kv_bool(&kc->kc_maths) = 1; + } else { + kstat_kv_timespec(&kc->kc_tnow) = ks->ks_updated; + kstat_kv_s64(&kc->kc_delta) = 0; + kstat_kv_s64(&kc->kc_diff) = 0; + kstat_kv_bool(&kc->kc_maths) = 0; + kstat_kv_u64(&kc->kc_cc) = 0; + kstat_kv_u64(&kc->kc_tc) = 0; + kstat_kv_u64(&kc->kc_cc_tc) = 0; + } + + kstat_kv_u32(&kc->kc_tc_reads) = sc->sc_timecounter_reads; + + return (0); +} + +static struct kstat * +mcx_kstat_attach_calibrate(struct mcx_softc *sc) +{ + struct kstat *ks; + struct mcx_kstat_calibrate *kc; + + ks = kstat_create(DEVNAME(sc), 0, "timestamp", 0, KSTAT_T_KV, 0); + if (ks == NULL) + return (NULL); + + kc = malloc(sizeof(*kc), M_DEVBUF, M_WAITOK); + + kstat_kv_init(&kc->kc_mhz, "device_mhz", KSTAT_KV_T_UINT32); + kstat_kv_u32(&kc->kc_mhz) = sc->sc_mhz; + kstat_kv_init(&kc->kc_khz, "device_khz", KSTAT_KV_T_UINT32); + kstat_kv_u32(&kc->kc_khz) = sc->sc_khz; + kstat_kv_init(&kc->kc_timestamp, "c_timestamp", KSTAT_KV_T_COUNTER64); + kstat_kv_init(&kc->kc_uptime, "c_uptime", KSTAT_KV_T_COUNTER64); + kstat_kv_init(&kc->kc_tbase, "c_tbase", KSTAT_KV_T_COUNTER64); + kstat_kv_init(&kc->kc_ubase, "c_ubase", KSTAT_KV_T_COUNTER64); + kstat_kv_init(&kc->kc_tdiff, "tdiff", KSTAT_KV_T_UINT64); + kstat_kv_init(&kc->kc_udiff, "udiff", KSTAT_KV_T_UINT64); + + kstat_kv_init(&kc->kc_timer, "timer", KSTAT_KV_T_COUNTER64); + kstat_kv_init(&kc->kc_tc, "cycles", KSTAT_KV_T_COUNTER64); + kstat_kv_init(&kc->kc_cc, "mcx cycles", KSTAT_KV_T_COUNTER64); + kstat_kv_init(&kc->kc_cc_tc, "diff cycles", KSTAT_KV_T_INT64); + kstat_kv_init(&kc->kc_know, "know", KSTAT_KV_T_MONOTIME); + kstat_kv_init(&kc->kc_tnow, "tnow", KSTAT_KV_T_MONOTIME); + kstat_kv_init(&kc->kc_diff, "know-tnow", KSTAT_KV_T_INT64); + kstat_kv_init(&kc->kc_delta, "delta", KSTAT_KV_T_INT64); + kstat_kv_init(&kc->kc_maths, "maths", KSTAT_KV_T_BOOL); + kstat_kv_init(&kc->kc_tc_reads, "tc_reads", KSTAT_KV_T_COUNTER32); + + ks->ks_softc = sc; + ks->ks_data = kc; + ks->ks_datalen = sizeof(*kc); + ks->ks_read = mcx_kstat_calibrate_read; + + kstat_install(ks); + + return (ks); +} + static void mcx_kstat_attach(struct mcx_softc *sc) { @@ -8197,6 +8393,8 @@ mcx_kstat_attach(struct mcx_softc *sc) mcx_kstat_attach_tmps(sc); mcx_kstat_attach_queues(sc); + + sc->sc_kstat_calibrate = mcx_kstat_attach_calibrate(sc); } static int @@ -8579,3 +8777,27 @@ out: } #endif /* NKSTAT > 0 */ + +static unsigned int +mcx_timecounter_read(struct timecounter *tc) +{ + struct mcx_softc *sc = tc->tc_priv; + + sc->sc_timecounter_reads++; + return (mcx_rd(sc, MCX_INTERNAL_TIMER_L)); +} + +static void +mcx_timecounter_attach(struct mcx_softc *sc) +{ + struct timecounter *tc = &sc->sc_timecounter; + + tc->tc_get_timecount = mcx_timecounter_read; + tc->tc_counter_mask = ~0U; + tc->tc_frequency = sc->sc_khz * 1000; + tc->tc_name = sc->sc_dev.dv_xname; + tc->tc_quality = -100; + tc->tc_priv = sc; + + tc_init(tc); +} Index: kern/kern_pledge.c =================================================================== RCS file: /cvs/src/sys/kern/kern_pledge.c,v retrieving revision 1.267 diff -u -p -r1.267 kern_pledge.c --- kern/kern_pledge.c 29 Oct 2020 21:15:27 -0000 1.267 +++ kern/kern_pledge.c 21 Dec 2020 05:13:42 -0000 @@ -1367,6 +1367,7 @@ pledge_sockopt(struct proc *p, int set, case SOL_SOCKET: switch (optname) { case SO_TIMESTAMP: + case SO_MONOSTAMP: return 0; } break; Index: kern/kern_tc.c =================================================================== RCS file: /cvs/src/sys/kern/kern_tc.c,v retrieving revision 1.70 diff -u -p -r1.70 kern_tc.c --- kern/kern_tc.c 5 Dec 2020 04:46:34 -0000 1.70 +++ kern/kern_tc.c 21 Dec 2020 05:13:42 -0000 @@ -72,7 +72,7 @@ struct timehands { struct bintime th_next_ntp_update; /* [T,W] */ int64_t th_adjustment; /* [W] */ u_int64_t th_scale; /* [W] */ - u_int th_offset_count; /* [W] */ + u_int64_t th_offset_count; /* [W] */ struct bintime th_boottime; /* [T,W] */ struct bintime th_offset; /* [W] */ struct bintime th_naptime; /* [W] */ @@ -80,6 +80,7 @@ struct timehands { struct timespec th_nanotime; /* [W] */ /* Fields not to be copied in tc_windup start with th_generation. */ volatile u_int th_generation; /* [W] */ + unsigned int th_version; /* [W] */ struct timehands *th_next; /* [I] */ }; @@ -116,21 +117,27 @@ volatile time_t time_uptime = 0; static int timestepwarnings; +volatile unsigned int __tc_version; + void ntp_update_second(struct timehands *); void tc_windup(struct bintime *, struct bintime *, int64_t *); +static inline u_int +tc_read(struct timehands *th) +{ + struct timecounter *tc = th->th_counter; + + return (tc->tc_get_timecount(tc) & tc->tc_counter_mask); +} + /* * Return the difference between the timehands' counter value now and what * was when we copied it to the timehands' offset_count. */ -static __inline u_int +static inline u_int tc_delta(struct timehands *th) { - struct timecounter *tc; - - tc = th->th_counter; - return ((tc->tc_get_timecount(tc) - th->th_offset_count) & - tc->tc_counter_mask); + return (tc_read(th) - (u_int)th->th_offset_count); } /* @@ -370,6 +377,42 @@ getmicrotime(struct timeval *tvp) } while (gen == 0 || gen != th->th_generation); } +void +timecycle(struct timecycle *tcyc) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + membar_consumer(); + tcyc->tcyc_cycles = th->th_offset_count + tc_delta(th); + tcyc->tcyc_scale = th->th_scale; + tcyc->tcyc_offset = th->th_offset; /* adjust? */ + tcyc->tcyc_version = th->th_version; + membar_consumer(); + } while (gen == 0 || gen != th->th_generation); +} + +void +gettimecycle(struct timecycle *tcyc) +{ + struct timehands *th; + u_int gen; + + do { + th = timehands; + gen = th->th_generation; + membar_consumer(); + tcyc->tcyc_cycles = th->th_offset_count; + tcyc->tcyc_scale = th->th_scale; + tcyc->tcyc_offset = th->th_offset; + tcyc->tcyc_version = th->th_version; + membar_consumer(); + } while (gen == 0 || gen != th->th_generation); +} + /* * Initialize a new timecounter and possibly use it. */ @@ -571,6 +614,7 @@ tc_windup(struct bintime *new_boottime, struct timehands *th, *tho; u_int64_t scale; u_int delta, ncount, ogen; + unsigned int nversion = 0; if (new_boottime != NULL || new_adjtimedelta != NULL) rw_assert_wrlock(&tc_lock); @@ -601,7 +645,6 @@ tc_windup(struct bintime *new_boottime, else ncount = 0; th->th_offset_count += delta; - th->th_offset_count &= th->th_counter->tc_counter_mask; bintimeaddfrac(&th->th_offset, th->th_scale * delta, &th->th_offset); /* @@ -633,8 +676,10 @@ tc_windup(struct bintime *new_boottime, * If changing the boot time or clock adjustment, do so before * NTP processing. */ - if (new_boottime != NULL) + if (new_boottime != NULL) { th->th_boottime = *new_boottime; + nversion = 1; + } if (new_adjtimedelta != NULL) { th->th_adjtimedelta = *new_adjtimedelta; /* Reset the NTP update period. */ @@ -662,6 +707,7 @@ tc_windup(struct bintime *new_boottime, if (th->th_counter != active_tc) { th->th_counter = active_tc; th->th_offset_count = ncount; + nversion = 1; } /*- @@ -699,6 +745,8 @@ tc_windup(struct bintime *new_boottime, */ if (++ogen == 0) ogen = 1; + + th->th_version = (__tc_version += nversion); membar_producer(); th->th_generation = ogen; Index: kern/uipc_mbuf.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_mbuf.c,v retrieving revision 1.276 diff -u -p -r1.276 uipc_mbuf.c --- kern/uipc_mbuf.c 12 Dec 2020 11:48:54 -0000 1.276 +++ kern/uipc_mbuf.c 21 Dec 2020 05:13:42 -0000 @@ -1470,6 +1470,15 @@ m_microtime(const struct mbuf *m, struct microtime(tv); } +void +m_nanouptime(const struct mbuf *m, struct timespec *ts) +{ + if (ISSET(m->m_pkthdr.csum_flags, M_TIMESTAMP)) + NSEC_TO_TIMESPEC(m->m_pkthdr.ph_timestamp, ts); + else + nanouptime(ts); +} + void * m_pool_alloc(struct pool *pp, int flags, int *slowdown) { Index: kern/uipc_socket.c =================================================================== RCS file: /cvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.251 diff -u -p -r1.251 uipc_socket.c --- kern/uipc_socket.c 12 Dec 2020 11:48:54 -0000 1.251 +++ kern/uipc_socket.c 21 Dec 2020 05:13:42 -0000 @@ -1728,6 +1728,7 @@ sosetopt(struct socket *so, int level, i case SO_OOBINLINE: case SO_TIMESTAMP: case SO_ZEROIZE: + case SO_MONOSTAMP: if (m == NULL || m->m_len < sizeof (int)) return (EINVAL); if (*mtod(m, int *)) @@ -1901,6 +1902,7 @@ sogetopt(struct socket *so, int level, i case SO_OOBINLINE: case SO_TIMESTAMP: case SO_ZEROIZE: + case SO_MONOSTAMP: *mtod(m, int *) = so->so_options & optname; break; Index: netinet/ip_input.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.352 diff -u -p -r1.352 ip_input.c --- netinet/ip_input.c 16 Nov 2020 06:44:38 -0000 1.352 +++ netinet/ip_input.c 21 Dec 2020 05:13:42 -0000 @@ -1704,6 +1704,15 @@ ip_savecontrol(struct inpcb *inp, struct if (*mp) mp = &(*mp)->m_next; } + if (inp->inp_socket->so_options & SO_MONOSTAMP) { + struct timespec ts; + + m_nanouptime(m, &ts); + *mp = sbcreatecontrol((caddr_t)&ts, sizeof(ts), + SCM_MONOSTAMP, SOL_SOCKET); + if (*mp) + mp = &(*mp)->m_next; + } if (inp->inp_flags & INP_RECVDSTADDR) { *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, Index: netinet/raw_ip.c =================================================================== RCS file: /cvs/src/sys/netinet/raw_ip.c,v retrieving revision 1.119 diff -u -p -r1.119 raw_ip.c --- netinet/raw_ip.c 4 Feb 2019 21:40:52 -0000 1.119 +++ netinet/raw_ip.c 21 Dec 2020 05:13:42 -0000 @@ -175,7 +175,8 @@ rip_input(struct mbuf **mp, int *offp, i if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) { if (last->inp_flags & INP_CONTROLOPTS || - last->inp_socket->so_options & SO_TIMESTAMP) + ISSET(last->inp_socket->so_options, + SO_TIMESTAMP|SO_MONOSTAMP)) ip_savecontrol(last, &opts, ip, n); if (sbappendaddr(last->inp_socket, &last->inp_socket->so_rcv, @@ -192,7 +193,8 @@ rip_input(struct mbuf **mp, int *offp, i } if (last) { if (last->inp_flags & INP_CONTROLOPTS || - last->inp_socket->so_options & SO_TIMESTAMP) + ISSET(last->inp_socket->so_options, + SO_TIMESTAMP|SO_MONOSTAMP)) ip_savecontrol(last, &opts, ip, m); if (sbappendaddr(last->inp_socket, &last->inp_socket->so_rcv, sintosa(&ripsrc), m, opts) == 0) { Index: netinet/udp_usrreq.c =================================================================== RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v retrieving revision 1.262 diff -u -p -r1.262 udp_usrreq.c --- netinet/udp_usrreq.c 22 Aug 2020 17:54:57 -0000 1.262 +++ netinet/udp_usrreq.c 21 Dec 2020 05:13:42 -0000 @@ -604,11 +604,11 @@ udp_sbappend(struct inpcb *inp, struct m #ifdef INET6 if (ip6 && (inp->inp_flags & IN6P_CONTROLOPTS || - so->so_options & SO_TIMESTAMP)) + ISSET(so->so_options, SO_TIMESTAMP|SO_MONOSTAMP))) ip6_savecontrol(inp, m, &opts); #endif /* INET6 */ if (ip && (inp->inp_flags & INP_CONTROLOPTS || - so->so_options & SO_TIMESTAMP)) + ISSET(so->so_options, SO_TIMESTAMP|SO_MONOSTAMP))) ip_savecontrol(inp, &opts, ip, m); #ifdef INET6 if (ip6 && (inp->inp_flags & IN6P_RECVDSTPORT)) { Index: netinet6/ip6_input.c =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_input.c,v retrieving revision 1.230 diff -u -p -r1.230 ip6_input.c --- netinet6/ip6_input.c 16 Nov 2020 06:44:39 -0000 1.230 +++ netinet6/ip6_input.c 21 Dec 2020 05:13:42 -0000 @@ -931,6 +931,15 @@ ip6_savecontrol(struct inpcb *in6p, stru if (*mp) mp = &(*mp)->m_next; } + if (in6p->inp_socket->so_options & SO_MONOSTAMP) { + struct timespec ts; + + m_nanouptime(m, &ts); + *mp = sbcreatecontrol((caddr_t)&ts, sizeof(ts), + SCM_MONOSTAMP, SOL_SOCKET); + if (*mp) + mp = &(*mp)->m_next; + } /* RFC 2292 sec. 5 */ if ((in6p->inp_flags & IN6P_PKTINFO) != 0) { Index: sys/kstat.h =================================================================== RCS file: /cvs/src/sys/sys/kstat.h,v retrieving revision 1.1 diff -u -p -r1.1 kstat.h --- sys/kstat.h 6 Jul 2020 03:56:51 -0000 1.1 +++ sys/kstat.h 21 Dec 2020 05:13:42 -0000 @@ -79,6 +79,10 @@ enum kstat_kv_type { KSTAT_KV_T_STR, /* trailing string */ KSTAT_KV_T_BYTES, /* trailing bytes */ KSTAT_KV_T_TEMP, /* temperature (uK) */ + + KSTAT_KV_T_REALTIME, /* struct timespec */ + KSTAT_KV_T_MONOTIME, /* struct timespec */ + KSTAT_KV_T_INTERVAL, /* struct timespec */ }; /* units only apply to integer types */ @@ -99,6 +103,7 @@ struct kstat_kv { uint32_t v_u32; int32_t v_s32; size_t v_len; + struct timespec v_timespec; } kv_v; enum kstat_kv_type kv_type; enum kstat_kv_unit kv_unit; @@ -112,6 +117,7 @@ struct kstat_kv { #define kstat_kv_s32(_kv) (_kv)->kv_v.v_s32 #define kstat_kv_len(_kv) (_kv)->kv_v.v_len #define kstat_kv_temp(_kv) (_kv)->kv_v.v_u64 +#define kstat_kv_timespec(_kv) (_kv)->kv_v.v_timespec #ifdef _KERNEL Index: sys/mbuf.h =================================================================== RCS file: /cvs/src/sys/sys/mbuf.h,v retrieving revision 1.251 diff -u -p -r1.251 mbuf.h --- sys/mbuf.h 12 Dec 2020 11:49:02 -0000 1.251 +++ sys/mbuf.h 21 Dec 2020 05:13:42 -0000 @@ -444,6 +444,7 @@ struct mbuf *m_dup_pkt(struct mbuf *, un int m_dup_pkthdr(struct mbuf *, struct mbuf *, int); void m_microtime(const struct mbuf *, struct timeval *); +void m_nanouptime(const struct mbuf *, struct timespec *); static inline struct mbuf * m_freemp(struct mbuf **mp) Index: sys/socket.h =================================================================== RCS file: /cvs/src/sys/sys/socket.h,v retrieving revision 1.99 diff -u -p -r1.99 socket.h --- sys/socket.h 29 Oct 2020 21:15:27 -0000 1.99 +++ sys/socket.h 21 Dec 2020 05:13:42 -0000 @@ -97,6 +97,7 @@ typedef __sa_family_t sa_family_t; /* so #define SO_TIMESTAMP 0x0800 /* timestamp received dgram traffic */ #define SO_BINDANY 0x1000 /* allow bind to any address */ #define SO_ZEROIZE 0x2000 /* zero out all mbufs sent over socket */ +#define SO_MONOSTAMP 0x4000 /* monotime stamp rxed dgram traffic */ /* * Additional options, not kept in so_options. @@ -523,6 +524,7 @@ struct cmsghdr { /* "Socket"-level control message types: */ #define SCM_RIGHTS 0x01 /* access rights (array of int) */ #define SCM_TIMESTAMP 0x04 /* timestamp (struct timeval) */ +#define SCM_MONOSTAMP 0x08 /* timestamp (struct timespec) */ #ifndef _KERNEL Index: sys/timetc.h =================================================================== RCS file: /cvs/src/sys/sys/timetc.h,v retrieving revision 1.12 diff -u -p -r1.12 timetc.h --- sys/timetc.h 6 Jul 2020 13:33:09 -0000 1.12 +++ sys/timetc.h 21 Dec 2020 05:13:42 -0000 @@ -117,6 +117,16 @@ extern struct timecounter *timecounter; extern struct uvm_object *timekeep_object; extern struct timekeep *timekeep; +struct timecycle { + uint64_t tcyc_cycles; + int64_t tcyc_scale; + struct bintime tcyc_offset; + unsigned int tcyc_version; +}; + +void timecycle(struct timecycle *); +void gettimecycle(struct timecycle *); + u_int64_t tc_getfrequency(void); u_int64_t tc_getprecision(void); void tc_init(struct timecounter *tc);