diff --git a/sys/dev/usb/serial/usb_serial.c b/sys/dev/usb/serial/usb_serial.c index ae4ed3a4339..46d08b5fedb 100644 --- a/sys/dev/usb/serial/usb_serial.c +++ b/sys/dev/usb/serial/usb_serial.c @@ -415,8 +415,9 @@ ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) sc->sc_tty = tp; sc->sc_pps.ppscap = PPS_CAPTUREBOTH; - sc->sc_pps.mtx = sc->sc_mtx; - pps_init(&sc->sc_pps); + sc->sc_pps.driver_abi = PPS_ABI_VERSION; + sc->sc_pps.driver_mtx = sc->sc_mtx; + pps_init_abi(&sc->sc_pps); DPRINTF("ttycreate: %s\n", buf); diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 6264c64e975..9dca0e80e5e 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -1468,6 +1468,17 @@ SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD, * RFC 2783 PPS-API implementation. */ +/* + * Return true if the driver is aware of the abi version extensions in the + * pps_state structure, and it supports at least the given abi version number. + */ +static inline int +abi_aware(struct pps_state *pps, int vers) +{ + + return ((pps->kcmode & KCMODE_ABIFLAG) && pps->driver_abi >= vers); +} + static int pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps) { @@ -1497,10 +1508,17 @@ pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps) cseq = pps->ppsinfo.clear_sequence; while (aseq == pps->ppsinfo.assert_sequence && cseq == pps->ppsinfo.clear_sequence) { - if (pps->mtx != NULL) - err = msleep(pps, pps->mtx, PCATCH, "ppsfch", timo); - else + if (abi_aware(pps, 1) && pps->driver_mtx != NULL) { + if (pps->flags & PPSFLAG_MTX_SPIN) { + err = msleep_spin(pps, pps->driver_mtx, + "ppsfch", timo); + } else { + err = msleep(pps, pps->driver_mtx, PCATCH, + "ppsfch", timo); + } + } else { err = tsleep(pps, PCATCH, "ppsfch", timo); + } if (err == EWOULDBLOCK && fapi->timeout.tv_sec == -1) { continue; } else if (err != 0) { @@ -1590,7 +1608,8 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) return (EINVAL); if (kapi->edge & ~pps->ppscap) return (EINVAL); - pps->kcmode = kapi->edge; + pps->kcmode = (kapi->edge & KCMODE_EDGEMASK) | + (pps->kcmode & KCMODE_ABIFLAG); return (0); #else return (EOPNOTSUPP); @@ -1611,6 +1630,18 @@ pps_init(struct pps_state *pps) #ifdef FFCLOCK pps->ppscap |= PPS_TSCLK_MASK; #endif + pps->kcmode &= ~KCMODE_ABIFLAG; +} + +void +pps_init_abi(struct pps_state *pps) +{ + + pps_init(pps); + if (pps->driver_abi > 0) { + pps->kcmode |= KCMODE_ABIFLAG; + pps->kernel_abi = PPS_ABI_VERSION; + } } void diff --git a/sys/sys/timepps.h b/sys/sys/timepps.h index ae4b84d17d7..d472c804dc4 100644 --- a/sys/sys/timepps.h +++ b/sys/sys/timepps.h @@ -135,6 +135,13 @@ struct pps_kcbind_args { struct mtx; +#define KCMODE_EDGEMASK 0x03 +#define KCMODE_ABIFLAG 0x80000000 /* Internal use: abi-aware driver. */ + +#define PPS_ABI_VERSION 1 + +#define PPSFLAG_MTX_SPIN 0x01 /* Driver mtx is MTX_SPIN type. */ + struct pps_state { /* Capture information. */ struct timehands *capth; @@ -142,9 +149,6 @@ struct pps_state { unsigned capgen; unsigned capcount; - /* pointer to mutex protecting this state, if any */ - struct mtx *mtx; - /* State information. */ pps_params_t ppsparam; pps_info_t ppsinfo; @@ -153,11 +157,19 @@ struct pps_state { int ppscap; struct timecounter *ppstc; unsigned ppscount[3]; + /* + * The following fields are valid if the driver calls pps_init_abi(). + */ + uint16_t driver_abi; /* Driver sets before pps_init_abi(). */ + uint16_t kernel_abi; /* Kernel sets during pps_init_abi(). */ + struct mtx *driver_mtx; /* Optional, valid if non-NULL. */ + uint32_t flags; }; void pps_capture(struct pps_state *pps); void pps_event(struct pps_state *pps, int event); void pps_init(struct pps_state *pps); +void pps_init_abi(struct pps_state *pps); int pps_ioctl(unsigned long cmd, caddr_t data, struct pps_state *pps); void hardpps(struct timespec *tsp, long nsec);