Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_tc.c
Show First 20 Lines • Show All 1,755 Lines • ▼ Show 20 Lines | if (pps->driver_abi > 0) { | ||||
pps->kernel_abi = PPS_ABI_VERSION; | pps->kernel_abi = PPS_ABI_VERSION; | ||||
} | } | ||||
} | } | ||||
void | void | ||||
pps_capture(struct pps_state *pps) | pps_capture(struct pps_state *pps) | ||||
{ | { | ||||
struct timehands *th; | struct timehands *th; | ||||
struct timecounter *tc; | |||||
KASSERT(pps != NULL, ("NULL pps pointer in pps_capture")); | KASSERT(pps != NULL, ("NULL pps pointer in pps_capture")); | ||||
th = timehands; | th = timehands; | ||||
pps->capgen = atomic_load_acq_int(&th->th_generation); | pps->capgen = atomic_load_acq_int(&th->th_generation); | ||||
pps->capth = th; | pps->capth = th; | ||||
#ifdef FFCLOCK | #ifdef FFCLOCK | ||||
pps->capffth = fftimehands; | pps->capffth = fftimehands; | ||||
#endif | #endif | ||||
pps->capcount = th->th_counter->tc_get_timecount(th->th_counter); | tc = th->th_counter; | ||||
atomic_thread_fence_acq(); | pps->capcount = tc->tc_get_timecount(tc); | ||||
if (pps->capgen != th->th_generation) | |||||
pps->capgen = 0; | |||||
} | } | ||||
void | void | ||||
pps_event(struct pps_state *pps, int event) | pps_event(struct pps_state *pps, int event) | ||||
{ | { | ||||
struct timehands *capth; | |||||
struct timecounter *captc; | |||||
uint64_t capth_scale; | |||||
struct bintime bt; | struct bintime bt; | ||||
struct timespec ts, *tsp, *osp; | struct timespec *tsp, *osp; | ||||
u_int tcount, *pcount; | u_int tcount, *pcount; | ||||
int foff; | int foff; | ||||
pps_seq_t *pseq; | pps_seq_t *pseq; | ||||
#ifdef FFCLOCK | #ifdef FFCLOCK | ||||
struct timespec *tsp_ffc; | struct timespec *tsp_ffc; | ||||
pps_seq_t *pseq_ffc; | pps_seq_t *pseq_ffc; | ||||
ffcounter *ffcount; | ffcounter *ffcount; | ||||
#endif | #endif | ||||
#ifdef PPS_SYNC | #ifdef PPS_SYNC | ||||
int fhard; | int fhard; | ||||
#endif | #endif | ||||
KASSERT(pps != NULL, ("NULL pps pointer in pps_event")); | KASSERT(pps != NULL, ("NULL pps pointer in pps_event")); | ||||
/* Nothing to do if not currently set to capture this event type. */ | /* Nothing to do if not currently set to capture this event type. */ | ||||
if ((event & pps->ppsparam.mode) == 0) | if ((event & pps->ppsparam.mode) == 0) | ||||
return; | return; | ||||
/* Make a snapshot of the captured timehand */ | |||||
capth = pps->capth; | |||||
captc = capth->th_counter; | |||||
capth_scale = capth->th_scale; | |||||
tcount = capth->th_offset_count; | |||||
bt = capth->th_bintime; | |||||
/* If the timecounter was wound up underneath us, bail out. */ | /* If the timecounter was wound up underneath us, bail out. */ | ||||
if (pps->capgen == 0 || pps->capgen != | atomic_thread_fence_acq(); | ||||
atomic_load_acq_int(&pps->capth->th_generation)) | if (pps->capgen == 0 || pps->capgen != capth->th_generation) | ||||
return; | return; | ||||
/* Things would be easier with arrays. */ | /* Things would be easier with arrays. */ | ||||
if (event == PPS_CAPTUREASSERT) { | if (event == PPS_CAPTUREASSERT) { | ||||
tsp = &pps->ppsinfo.assert_timestamp; | tsp = &pps->ppsinfo.assert_timestamp; | ||||
osp = &pps->ppsparam.assert_offset; | osp = &pps->ppsparam.assert_offset; | ||||
foff = pps->ppsparam.mode & PPS_OFFSETASSERT; | foff = pps->ppsparam.mode & PPS_OFFSETASSERT; | ||||
#ifdef PPS_SYNC | #ifdef PPS_SYNC | ||||
Show All 17 Lines | #endif | ||||
pseq = &pps->ppsinfo.clear_sequence; | pseq = &pps->ppsinfo.clear_sequence; | ||||
#ifdef FFCLOCK | #ifdef FFCLOCK | ||||
ffcount = &pps->ppsinfo_ffc.clear_ffcount; | ffcount = &pps->ppsinfo_ffc.clear_ffcount; | ||||
tsp_ffc = &pps->ppsinfo_ffc.clear_timestamp; | tsp_ffc = &pps->ppsinfo_ffc.clear_timestamp; | ||||
pseq_ffc = &pps->ppsinfo_ffc.clear_sequence; | pseq_ffc = &pps->ppsinfo_ffc.clear_sequence; | ||||
#endif | #endif | ||||
} | } | ||||
*pcount = pps->capcount; | |||||
/* | /* | ||||
* If the timecounter changed, we cannot compare the count values, so | * If the timecounter changed, we cannot compare the count values, so | ||||
* we have to drop the rest of the PPS-stuff until the next event. | * we have to drop the rest of the PPS-stuff until the next event. | ||||
*/ | */ | ||||
if (pps->ppstc != pps->capth->th_counter) { | if (__predict_false(pps->ppstc != captc)) { | ||||
pps->ppstc = pps->capth->th_counter; | pps->ppstc = captc; | ||||
*pcount = pps->capcount; | |||||
pps->ppscount[2] = pps->capcount; | pps->ppscount[2] = pps->capcount; | ||||
return; | return; | ||||
} | } | ||||
/* Convert the count to a timespec. */ | |||||
tcount = pps->capcount - pps->capth->th_offset_count; | |||||
tcount &= pps->capth->th_counter->tc_counter_mask; | |||||
bt = pps->capth->th_bintime; | |||||
bintime_addx(&bt, pps->capth->th_scale * tcount); | |||||
bintime2timespec(&bt, &ts); | |||||
/* If the timecounter was wound up underneath us, bail out. */ | |||||
atomic_thread_fence_acq(); | |||||
if (pps->capgen != pps->capth->th_generation) | |||||
return; | |||||
*pcount = pps->capcount; | |||||
(*pseq)++; | (*pseq)++; | ||||
*tsp = ts; | |||||
/* Convert the count to a timespec. */ | |||||
tcount = pps->capcount - tcount; | |||||
tcount &= captc->tc_counter_mask; | |||||
bintime_addx(&bt, capth_scale * tcount); | |||||
bintime2timespec(&bt, tsp); | |||||
if (foff) { | if (foff) { | ||||
timespecadd(tsp, osp, tsp); | timespecadd(tsp, osp, tsp); | ||||
if (tsp->tv_nsec < 0) { | if (tsp->tv_nsec < 0) { | ||||
tsp->tv_nsec += 1000000000; | tsp->tv_nsec += 1000000000; | ||||
tsp->tv_sec -= 1; | tsp->tv_sec -= 1; | ||||
} | } | ||||
} | } | ||||
#ifdef FFCLOCK | #ifdef FFCLOCK | ||||
*ffcount = pps->capffth->tick_ffcount + tcount; | *ffcount = pps->capffth->tick_ffcount + tcount; | ||||
bt = pps->capffth->tick_time; | bt = pps->capffth->tick_time; | ||||
ffclock_convert_delta(tcount, pps->capffth->cest.period, &bt); | ffclock_convert_delta(tcount, pps->capffth->cest.period, &bt); | ||||
bintime_add(&bt, &pps->capffth->tick_time); | bintime_add(&bt, &pps->capffth->tick_time); | ||||
bintime2timespec(&bt, &ts); | |||||
(*pseq_ffc)++; | (*pseq_ffc)++; | ||||
*tsp_ffc = ts; | bintime2timespec(&bt, tsp_ffc); | ||||
#endif | #endif | ||||
#ifdef PPS_SYNC | #ifdef PPS_SYNC | ||||
if (fhard) { | if (fhard) { | ||||
uint64_t scale; | uint64_t nsec; | ||||
uint64_t freq; | |||||
/* | /* | ||||
* Feed the NTP PLL/FLL. | * Feed the NTP PLL/FLL. | ||||
* The FLL wants to know how many (hardware) nanoseconds | * The FLL wants to know how many (hardware) nanoseconds | ||||
* elapsed since the previous event. | * elapsed since the previous event. | ||||
*/ | */ | ||||
tcount = pps->capcount - pps->ppscount[2]; | tcount = pps->capcount - pps->ppscount[2]; | ||||
pps->ppscount[2] = pps->capcount; | pps->ppscount[2] = pps->capcount; | ||||
tcount &= pps->capth->th_counter->tc_counter_mask; | tcount &= captc->tc_counter_mask; | ||||
scale = (uint64_t)1 << 63; | nsec = 1000000000; | ||||
scale /= pps->capth->th_counter->tc_frequency; | nsec *= tcount; | ||||
scale *= 2; | freq = captc->tc_frequency; | ||||
bt.sec = 0; | nsec = (nsec + freq / 2) / freq; | ||||
bt.frac = 0; | hardpps(tsp, (long)nsec); | ||||
bintime_addx(&bt, scale * tcount); | |||||
bintime2timespec(&bt, &ts); | |||||
hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec); | |||||
} | } | ||||
#endif | #endif | ||||
/* Wakeup anyone sleeping in pps_fetch(). */ | /* Wakeup anyone sleeping in pps_fetch(). */ | ||||
wakeup(pps); | wakeup(pps); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 356 Lines • Show Last 20 Lines |