Re: git: 26d6617f3e54 - main - watchdog: Convert to using sbintime_t format

From: Mitchell Horne <mhorne_at_freebsd.org>
Date: Tue, 19 Aug 2025 19:25:18 UTC
On 8/14/25 16:03, Justin Hibbits wrote:
> The branch main has been updated by jhibbits:
> 
> URL: https://cgit.FreeBSD.org/src/commit/?id=26d6617f3e5406d9f92d87674f1667dd856828a3
> 
> commit 26d6617f3e5406d9f92d87674f1667dd856828a3
> Author:     Justin Hibbits <jhibbits@FreeBSD.org>
> AuthorDate: 2025-02-26 20:25:36 +0000
> Commit:     Justin Hibbits <jhibbits@FreeBSD.org>
> CommitDate: 2025-08-14 19:02:46 +0000
> 
>     watchdog: Convert to using sbintime_t format
>     
>     Summary:
>     Some watchdogs are now based on a countdown timer instead of a bit
>     check.  To deal with these, convert the watchdog framework to use
>     sbintime_t instead of power-of-2-nanoseconds.  This allows more
>     precision, and more variety of watchdog timeouts.  Keep the old method
>     as a compatibility layer, so that drivers can be migrated slowly, as
>     needed.

Hi Justin,

The watchdog(4) man page needs to be updated for the new ioctl API. Can
you please handle this?

There is also the watchdog(9) page, which is of lower quality and
detail. I would not insist on changes here, but I do note that it is
affected.

Best,
Mitchell

>     
>     Reviewed by:    jhb
>     Sponsored by:   Juniper Networks, Inc.
>     Differential Revision: https://reviews.freebsd.org/D49183
> ---
>  sys/dev/watchdog/watchdog.c    | 202 ++++++++++++++++++++++-------------------
>  sys/sys/watchdog.h             |  17 ++--
>  usr.sbin/watchdogd/watchdogd.c |  99 +++++---------------
>  3 files changed, 143 insertions(+), 175 deletions(-)
> 
> diff --git a/sys/dev/watchdog/watchdog.c b/sys/dev/watchdog/watchdog.c
> index c0babef1b29b..e1b2e08c3f10 100644
> --- a/sys/dev/watchdog/watchdog.c
> +++ b/sys/dev/watchdog/watchdog.c
> @@ -50,11 +50,20 @@
>  
>  #include <sys/syscallsubr.h> /* kern_clock_gettime() */
>  
> -static int wd_set_pretimeout(int newtimeout, int disableiftoolong);
> +#ifdef	COMPAT_FREEBSD14
> +#define WDIOCPATPAT_14	_IOW('W', 42, u_int)	/* pat the watchdog */
> +#define WDIOC_SETTIMEOUT_14   _IOW('W', 43, int)	/* set/reset the timer */
> +#define WDIOC_GETTIMEOUT_14    _IOR('W', 44, int)	/* get total timeout */
> +#define WDIOC_GETTIMELEFT_14   _IOR('W', 45, int)	/* get time left */
> +#define WDIOC_GETPRETIMEOUT_14 _IOR('W', 46, int)	/* get the pre-timeout */
> +#define WDIOC_SETPRETIMEOUT_14 _IOW('W', 47, int)	/* set the pre-timeout */
> +#endif
> +
> +static int wd_set_pretimeout(sbintime_t newtimeout, int disableiftoolong);
>  static void wd_timeout_cb(void *arg);
>  
>  static struct callout wd_pretimeo_handle;
> -static int wd_pretimeout;
> +static sbintime_t wd_pretimeout;
>  static int wd_pretimeout_act = WD_SOFT_LOG;
>  
>  static struct callout wd_softtimeo_handle;
> @@ -63,6 +72,8 @@ static int wd_softtimer;	/* true = use softtimer instead of hardware
>  static int wd_softtimeout_act = WD_SOFT_LOG;	/* action for the software timeout */
>  
>  static struct cdev *wd_dev;
> +static volatile sbintime_t wd_last_sbt;	/* last timeout value (sbt) */
> +static sbintime_t wd_last_sbt_sysctl;	/* last timeout value (sbt) */
>  static volatile u_int wd_last_u;    /* last timeout value set by kern_do_pat */
>  static u_int wd_last_u_sysctl;    /* last timeout value set by kern_do_pat */
>  static u_int wd_last_u_sysctl_secs;    /* wd_last_u in seconds */
> @@ -73,6 +84,8 @@ SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u, CTLFLAG_RD,
>      &wd_last_u_sysctl, 0, "Watchdog last update time");
>  SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u_secs, CTLFLAG_RD,
>      &wd_last_u_sysctl_secs, 0, "Watchdog last update time");
> +SYSCTL_SBINTIME_MSEC(_hw_watchdog, OID_AUTO, wd_last_msecs, CTLFLAG_RD,
> +    &wd_last_sbt_sysctl, "Watchdog last update time (milliseconds)");
>  
>  static int wd_lastpat_valid = 0;
>  static time_t wd_lastpat = 0;	/* when the watchdog was last patted */
> @@ -80,41 +93,26 @@ static time_t wd_lastpat = 0;	/* when the watchdog was last patted */
>  /* Hook for external software watchdog to register for use if needed */
>  void (*wdog_software_attach)(void);
>  
> -static void
> -pow2ns_to_ts(int pow2ns, struct timespec *ts)
> +/* Legacy interface to watchdog. */
> +int
> +wdog_kern_pat(u_int utim)
>  {
> -	uint64_t ns;
> +	sbintime_t sbt;
>  
> -	ns = 1ULL << pow2ns;
> -	ts->tv_sec = ns / 1000000000ULL;
> -	ts->tv_nsec = ns % 1000000000ULL;
> -}
> +	if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0)
> +		return (EINVAL);
>  
> -static int
> -pow2ns_to_ticks(int pow2ns)
> -{
> -	struct timeval tv;
> -	struct timespec ts;
> +	if ((utim & WD_LASTVAL) != 0) {
> +		return (wdog_control(WD_CTRL_RESET));
> +	}
>  
> -	pow2ns_to_ts(pow2ns, &ts);
> -	TIMESPEC_TO_TIMEVAL(&tv, &ts);
> -	return (tvtohz(&tv));
> -}
> +	utim &= WD_INTERVAL;
> +	if (utim == WD_TO_NEVER)
> +		sbt = 0;
> +	else
> +		sbt = nstosbt(1 << utim);
>  
> -static int
> -seconds_to_pow2ns(int seconds)
> -{
> -	uint64_t power;
> -	uint64_t ns;
> -	uint64_t shifted;
> -
> -	ns = ((uint64_t)seconds) * 1000000000ULL;
> -	power = flsll(ns);
> -	shifted = 1ULL << power;
> -	if (shifted <= ns) {
> -		power++;
> -	}
> -	return (power);
> +	return (wdog_kern_pat_sbt(sbt));
>  }
>  
>  int
> @@ -126,76 +124,63 @@ wdog_control(int ctrl)
>  	}
>  
>  	if ((ctrl & WD_CTRL_RESET) != 0) {
> -		wdog_kern_pat(WD_ACTIVE | WD_LASTVAL);
> +		wdog_kern_pat_sbt(wd_last_sbt);
>  	} else if ((ctrl & WD_CTRL_ENABLE) != 0) {
> -		wdog_kern_pat(WD_ACTIVE | WD_LASTVAL);
> +		wdog_kern_pat_sbt(wd_last_sbt);
>  	}
>  
>  	return (0);
>  }
>  
>  int
> -wdog_kern_pat(u_int utim)
> +wdog_kern_pat_sbt(sbintime_t sbt)
>  {
> -	int error;
> -	static int first = 1;
> -
> -	if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0)
> -		return (EINVAL);
> -
> -	if ((utim & WD_LASTVAL) != 0) {
> -		/*
> -		 * if WD_LASTVAL is set, fill in the bits for timeout
> -		 * from the saved value in wd_last_u.
> -		 */
> -		MPASS((wd_last_u & ~WD_INTERVAL) == 0);
> -		utim &= ~WD_LASTVAL;
> -		utim |= wd_last_u;
> -	} else {
> -		/*
> -		 * Otherwise save the new interval.
> -		 * This can be zero (to disable the watchdog)
> -		 */
> -		wd_last_u = (utim & WD_INTERVAL);
> +	sbintime_t error_sbt = 0;
> +	int pow2ns = 0;
> +	int error = 0;
> +	static bool first = true;
> +
> +	/* legacy uses power-of-2-nanoseconds time. */
> +	if (sbt != 0) {
> +		pow2ns = flsl(sbttons(sbt));
> +	}
> +	if (wd_last_sbt != sbt) {
> +		wd_last_u = pow2ns;
>  		wd_last_u_sysctl = wd_last_u;
> -		wd_last_u_sysctl_secs = pow2ns_to_ticks(wd_last_u) / hz;
> +		wd_last_u_sysctl_secs = sbt / SBT_1S;
> +
> +		wd_last_sbt = sbt;
>  	}
> -	if ((utim & WD_INTERVAL) == WD_TO_NEVER) {
> -		utim = 0;
>  
> -		/* Assume all is well; watchdog signals failure. */
> -		error = 0;
> -	} else {
> -		/* Assume no watchdog available; watchdog flags success */
> +	if (sbt != 0)
>  		error = EOPNOTSUPP;
> -	}
> +
>  	if (wd_softtimer) {
> -		if (utim == 0) {
> +		if (sbt == 0) {
>  			callout_stop(&wd_softtimeo_handle);
>  		} else {
> -			(void) callout_reset(&wd_softtimeo_handle,
> -			    pow2ns_to_ticks(utim), wd_timeout_cb, "soft");
> +			(void) callout_reset_sbt(&wd_softtimeo_handle,
> +			    sbt, 0, wd_timeout_cb, "soft", 0);
>  		}
>  		error = 0;
>  	} else {
> -		EVENTHANDLER_INVOKE(watchdog_list, utim, &error);
> +		EVENTHANDLER_INVOKE(watchdog_sbt_list, sbt, &error_sbt, &error);
> +		EVENTHANDLER_INVOKE(watchdog_list, pow2ns, &error);
>  	}
>  	/*
> -	 * If we no hardware watchdog responded, we have not tried to
> +	 * If no hardware watchdog responded, we have not tried to
>  	 * attach an external software watchdog, and one is available,
>  	 * attach it now and retry.
>  	 */
> -	if (error == EOPNOTSUPP && first && *wdog_software_attach != NULL) {
> +	if (error == EOPNOTSUPP && first && wdog_software_attach != NULL) {
>  		(*wdog_software_attach)();
> -		EVENTHANDLER_INVOKE(watchdog_list, utim, &error);
> +		EVENTHANDLER_INVOKE(watchdog_sbt_list, sbt, &error_sbt, &error);
> +		EVENTHANDLER_INVOKE(watchdog_list, pow2ns, &error);
>  	}
> -	first = 0;
> +	first = false;
>  
> +	/* TODO: Print a (rate limited?) warning if error_sbt is too far away */
>  	wd_set_pretimeout(wd_pretimeout, true);
> -	/*
> -	 * If we were able to arm/strobe the watchdog, then
> -	 * update the last time it was strobed for WDIOC_GETTIMELEFT
> -	 */
>  	if (!error) {
>  		struct timespec ts;
>  
> @@ -206,6 +191,7 @@ wdog_kern_pat(u_int utim)
>  			wd_lastpat_valid = 1;
>  		}
>  	}
> +
>  	return (error);
>  }
>  
> @@ -282,16 +268,14 @@ wd_timeout_cb(void *arg)
>   * current actual watchdog timeout.
>   */
>  static int
> -wd_set_pretimeout(int newtimeout, int disableiftoolong)
> +wd_set_pretimeout(sbintime_t newtimeout, int disableiftoolong)
>  {
> -	u_int utime;
> -	struct timespec utime_ts;
> -	int timeout_ticks;
> +	sbintime_t utime;
> +	sbintime_t timeout_left;
>  
> -	utime = wdog_kern_last_timeout();
> -	pow2ns_to_ts(utime, &utime_ts);
> +	utime = wdog_kern_last_timeout_sbt();
>  	/* do not permit a pre-timeout >= than the timeout. */
> -	if (newtimeout >= utime_ts.tv_sec) {
> +	if (newtimeout >= utime) {
>  		/*
>  		 * If 'disableiftoolong' then just fall through
>  		 * so as to disable the pre-watchdog
> @@ -309,7 +293,7 @@ wd_set_pretimeout(int newtimeout, int disableiftoolong)
>  		return 0;
>  	}
>  
> -	timeout_ticks = pow2ns_to_ticks(utime) - (hz*newtimeout);
> +	timeout_left = utime - newtimeout;
>  #if 0
>  	printf("wd_set_pretimeout: "
>  	    "newtimeout: %d, "
> @@ -323,8 +307,8 @@ wd_set_pretimeout(int newtimeout, int disableiftoolong)
>  #endif
>  
>  	/* We determined the value is sane, so reset the callout */
> -	(void) callout_reset(&wd_pretimeo_handle,
> -	    timeout_ticks, wd_timeout_cb, "pre");
> +	(void) callout_reset_sbt(&wd_pretimeo_handle,
> +	    timeout_left, 0, wd_timeout_cb, "pre", 0);
>  	wd_pretimeout = newtimeout;
>  	return 0;
>  }
> @@ -333,6 +317,7 @@ static int
>  wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
>      int flags __unused, struct thread *td)
>  {
> +	sbintime_t sb;
>  	u_int u;
>  	time_t timeleft;
>  	int error;
> @@ -368,32 +353,55 @@ wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
>  			error = EINVAL;
>  		}
>  		break;
> -	case WDIOC_GETPRETIMEOUT:
> -		*(int *)data = (int)wd_pretimeout;
> +#ifdef	COMPAT_FREEBSD14
> +	case WDIOC_GETPRETIMEOUT_14:
> +		*(int *)data = (int)(wd_pretimeout / SBT_1S);
>  		break;
> -	case WDIOC_SETPRETIMEOUT:
> -		error = wd_set_pretimeout(*(int *)data, false);
> +	case WDIOC_SETPRETIMEOUT_14:
> +		error = wd_set_pretimeout(*(int *)data * SBT_1S, false);
>  		break;
> -	case WDIOC_GETTIMELEFT:
> +	case WDIOC_GETTIMELEFT_14:
>  		error = wd_get_time_left(td, &timeleft);
>  		if (error)
>  			break;
>  		*(int *)data = (int)timeleft;
>  		break;
> -	case WDIOC_SETTIMEOUT:
> +	case WDIOC_SETTIMEOUT_14:
>  		u = *(u_int *)data;
> -		error = wdog_kern_pat(seconds_to_pow2ns(u));
> +		error = wdog_kern_pat_sbt(mstosbt(u * 1000ULL));
>  		break;
> -	case WDIOC_GETTIMEOUT:
> +	case WDIOC_GETTIMEOUT_14:
>  		u = wdog_kern_last_timeout();
>  		*(u_int *)data = u;
>  		break;
> -	case WDIOCPATPAT:
> +	case WDIOCPATPAT_14:
>  		error = wd_ioctl_patpat(data);
>  		break;
> +#endif
> +
> +	/* New API */
>  	case WDIOC_CONTROL:
>  		wdog_control(*(int *)data);
>  		break;
> +	case WDIOC_SETTIMEOUT:
> +		sb = *(sbintime_t *)data;
> +		error = wdog_kern_pat_sbt(sb);
> +		break;
> +	case WDIOC_GETTIMEOUT:
> +		*(sbintime_t *)data = wdog_kern_last_timeout_sbt();
> +		break;
> +	case WDIOC_GETTIMELEFT:
> +		error = wd_get_time_left(td, &timeleft);
> +		if (error)
> +			break;
> +		*(sbintime_t *)data = (sbintime_t)timeleft * SBT_1S;
> +		break;
> +	case WDIOC_GETPRETIMEOUT:
> +		*(sbintime_t *)data = wd_pretimeout;
> +		break;
> +	case WDIOC_SETPRETIMEOUT:
> +		error = wd_set_pretimeout(*(sbintime_t *)data, false);
> +		break;
>  	default:
>  		error = ENOIOCTL;
>  		break;
> @@ -412,6 +420,12 @@ wdog_kern_last_timeout(void)
>  	return (wd_last_u);
>  }
>  
> +sbintime_t
> +wdog_kern_last_timeout_sbt(void)
> +{
> +	return (wd_last_sbt);
> +}
> +
>  static struct cdevsw wd_cdevsw = {
>  	.d_version =	D_VERSION,
>  	.d_ioctl =	wd_ioctl,
> diff --git a/sys/sys/watchdog.h b/sys/sys/watchdog.h
> index 3c9d31eb577b..8401d343a6b7 100644
> --- a/sys/sys/watchdog.h
> +++ b/sys/sys/watchdog.h
> @@ -32,15 +32,16 @@
>  #define	_SYS_WATCHDOG_H
>  
>  #include <sys/ioccom.h>
> +#include <sys/_types.h>
>  
>  #define	_PATH_WATCHDOG	"fido"
>  
> -#define WDIOCPATPAT	_IOW('W', 42, u_int)	/* pat the watchdog */
> -#define WDIOC_SETTIMEOUT    _IOW('W', 43, int)	/* set/reset the timer */
> -#define WDIOC_GETTIMEOUT    _IOR('W', 44, int)	/* get total timeout */
> -#define WDIOC_GETTIMELEFT   _IOR('W', 45, int)	/* get time left */
> -#define WDIOC_GETPRETIMEOUT _IOR('W', 46, int)	/* get the pre-timeout */
> -#define WDIOC_SETPRETIMEOUT _IOW('W', 47, int)	/* set the pre-timeout */
> +#define WDIOC_PATPAT	    _IOW('W', 52, sbintime_t)	/* pat the watchdog */
> +#define WDIOC_SETTIMEOUT    _IOW('W', 53, sbintime_t)	/* set/reset the timer */
> +#define WDIOC_GETTIMEOUT    _IOR('W', 54, sbintime_t)	/* get total timeout */
> +#define WDIOC_GETTIMELEFT   _IOR('W', 55, sbintime_t)	/* get time left */
> +#define WDIOC_GETPRETIMEOUT _IOR('W', 56, sbintime_t)	/* get the pre-timeout */
> +#define WDIOC_SETPRETIMEOUT _IOW('W', 57, sbintime_t)	/* set the pre-timeout */
>  /* set the action when a pre-timeout occurs see: WD_SOFT_* */
>  #define WDIOC_SETPRETIMEOUTACT _IOW('W', 48, int)
>  
> @@ -112,11 +113,15 @@
>  #include <sys/_eventhandler.h>
>  
>  typedef void (*watchdog_fn)(void *, u_int, int *);
> +typedef void (*watchdog_sbt_fn)(void *, sbintime_t, sbintime_t *, int *);
>  
>  EVENTHANDLER_DECLARE(watchdog_list, watchdog_fn);
> +EVENTHANDLER_DECLARE(watchdog_sbt_list, watchdog_sbt_fn);
>  
>  u_int	wdog_kern_last_timeout(void);
>  int	wdog_kern_pat(u_int utim);
> +sbintime_t	wdog_kern_last_timeout_sbt(void);
> +int		wdog_kern_pat_sbt(sbintime_t utim);
>  int		wdog_control(int ctrl);
>  
>  /*
> diff --git a/usr.sbin/watchdogd/watchdogd.c b/usr.sbin/watchdogd/watchdogd.c
> index 228438955006..27123f2143d0 100644
> --- a/usr.sbin/watchdogd/watchdogd.c
> +++ b/usr.sbin/watchdogd/watchdogd.c
> @@ -63,25 +63,25 @@
>  static long	fetchtimeout(int opt,
>      const char *longopt, const char *myoptarg, int zero_ok);
>  static void	parseargs(int, char *[]);
> -static int	seconds_to_pow2ns(int);
>  static void	sighandler(int);
>  static void	watchdog_loop(void);
>  static int	watchdog_init(void);
>  static int	watchdog_onoff(int onoff);
> -static int	watchdog_patpat(u_int timeout);
> +static int	watchdog_patpat(sbintime_t);
>  static void	usage(void);
> -static int	tstotv(struct timeval *tv, struct timespec *ts);
>  static int	tvtohz(struct timeval *tv);
>  
>  static int debugging = 0;
>  static int end_program = 0;
>  static const char *pidfile = _PATH_VARRUN "watchdogd.pid";
> -static u_int timeout = WD_TO_128SEC;
> +static sbintime_t timeout = 128 * SBT_1S;
>  static u_int exit_timeout = WD_TO_NEVER;
>  static u_int pretimeout = 0;
>  static u_int timeout_sec;
>  static u_int nap = 10;
> +#ifdef notyet
>  static int passive = 0;
> +#endif
>  static int is_daemon = 0;
>  static int is_dry_run = 0;  /* do not arm the watchdog, only
>  			       report on timing of the watch
> @@ -174,38 +174,23 @@ main(int argc, char *argv[])
>  		pidfile_remove(pfh);
>  		return (EX_OK);
>  	} else {
> -		if (passive)
> -			timeout |= WD_PASSIVE;
> -		else
> -			timeout |= WD_ACTIVE;
>  		if (watchdog_patpat(timeout) < 0)
>  			err(EX_OSERR, "patting the dog");
>  		return (EX_OK);
>  	}
>  }
>  
> -static void
> -pow2ns_to_ts(int pow2ns, struct timespec *ts)
> -{
> -	uint64_t ns;
> -
> -	ns = 1ULL << pow2ns;
> -	ts->tv_sec = ns / 1000000000ULL;
> -	ts->tv_nsec = ns % 1000000000ULL;
> -}
> -
>  /*
>   * Convert a timeout in seconds to N where 2^N nanoseconds is close to
>   * "seconds".
>   *
>   * The kernel expects the timeouts for watchdogs in "2^N nanosecond format".
>   */
> -static u_int
> -parse_timeout_to_pow2ns(char opt, const char *longopt, const char *myoptarg)
> +static sbintime_t
> +parse_timeout_to_sbt(char opt, const char *longopt, const char *myoptarg)
>  {
> -	double a;
> -	u_int rv;
> -	struct timespec ts;
> +	long a;
> +	sbintime_t rv;
>  	struct timeval tv;
>  	int ticks;
>  	char shortopt[] = "- ";
> @@ -216,19 +201,17 @@ parse_timeout_to_pow2ns(char opt, const char *longopt, const char *myoptarg)
>  	a = fetchtimeout(opt, longopt, myoptarg, 1);
>  
>  	if (a == 0)
> -		rv = WD_TO_NEVER;
> +		rv = 0;
>  	else
> -		rv = seconds_to_pow2ns(a);
> -	pow2ns_to_ts(rv, &ts);
> -	tstotv(&tv, &ts);
> +		rv = a * SBT_1S;
> +	tv = sbttotv(rv);
>  	ticks = tvtohz(&tv);
>  	if (debugging) {
>  		printf("Timeout for %s%s "
> -		    "is 2^%d nanoseconds "
> -		    "(in: %s sec -> out: %jd sec %ld ns -> %d ticks)\n",
> +		    "is "
> +		    "(in: %s sec -> out: %jd sec %ld us -> %d ticks)\n",
>  		    longopt ? "-" : "", longopt ? longopt : shortopt,
> -		    rv,
> -		    myoptarg, (intmax_t)ts.tv_sec, ts.tv_nsec, ticks);
> +		    myoptarg, (intmax_t)tv.tv_sec, tv.tv_usec, ticks);
>  	}
>  	if (ticks <= 0) {
>  		errx(1, "Timeout for %s%s is too small, please choose a higher timeout.", longopt ? "-" : "", longopt ? longopt : shortopt);
> @@ -364,7 +347,7 @@ watchdog_loop(void)
>  		}
>  
>  		if (failed == 0)
> -			watchdog_patpat(timeout|WD_ACTIVE);
> +			watchdog_patpat(timeout);
>  
>  		waited = watchdog_check_dogfunction_time(&ts_start, &ts_end);
>  		if (nap - waited > 0)
> @@ -387,13 +370,13 @@ try_end:
>   * to keep the watchdog from firing.
>   */
>  static int
> -watchdog_patpat(u_int t)
> +watchdog_patpat(sbintime_t sbt)
>  {
>  
>  	if (is_dry_run)
>  		return 0;
>  
> -	return ioctl(fd, WDIOCPATPAT, &t);
> +	return ioctl(fd, WDIOC_SETTIMEOUT, &sbt);
>  }
>  
>  static int
> @@ -429,7 +412,7 @@ watchdog_onoff(int onoff)
>  			warn("setting WDIOC_SETSOFT %d", softtimeout_set);
>  			return (error);
>  		}
> -		error = watchdog_patpat((timeout|WD_ACTIVE));
> +		error = watchdog_patpat(timeout);
>  		if (error) {
>  			warn("watchdog_patpat failed");
>  			goto failsafe;
> @@ -461,7 +444,7 @@ watchdog_onoff(int onoff)
>  			}
>  		}
>  		/* pat one more time for good measure */
> -		return watchdog_patpat((timeout|WD_ACTIVE));
> +		return watchdog_patpat(timeout);
>  	 } else {
>  		return watchdog_control(WD_CTRL_DISABLE);
>  	 }
> @@ -576,15 +559,6 @@ timeout_act_str2int(const char *lopt, const char *acts)
>  	return rv;
>  }
>  
> -int
> -tstotv(struct timeval *tv, struct timespec *ts)
> -{
> -
> -	tv->tv_sec = ts->tv_sec;
> -	tv->tv_usec = ts->tv_nsec / 1000;
> -	return 0;
> -}
> -
>  /*
>   * Convert a timeval to a number of ticks.
>   * Mostly copied from the kernel.
> @@ -656,30 +630,6 @@ tvtohz(struct timeval *tv)
>  	return ((int)ticks);
>  }
>  
> -static int
> -seconds_to_pow2ns(int seconds)
> -{
> -	uint64_t power;
> -	uint64_t ns;
> -	uint64_t shifted;
> -
> -	if (seconds <= 0)
> -		errx(1, "seconds %d < 0", seconds);
> -	ns = ((uint64_t)seconds) * 1000000000ULL;
> -	power = flsll(ns);
> -	shifted = 1ULL << power;
> -	if (shifted <= ns) {
> -		power++;
> -	}
> -	if (debugging) {
> -		printf("shifted %lld\n", (long long)shifted);
> -		printf("seconds_to_pow2ns: seconds: %d, ns %lld, power %d\n",
> -		    seconds, (long long)ns, (int)power);
> -	}
> -	return (power);
> -}
> -
> -
>  /*
>   * Handle the few command line arguments supported.
>   */
> @@ -692,8 +642,7 @@ parseargs(int argc, char *argv[])
>  	const char *lopt;
>  
>  	/* Get the default value of timeout_sec from the default timeout. */
> -	pow2ns_to_ts(timeout, &ts);
> -	timeout_sec = ts.tv_sec;
> +	timeout_sec = sbintime_getsec(timeout);
>  
>  	/*
>  	 * if we end with a 'd' aka 'watchdogd' then we are the daemon program,
> @@ -736,10 +685,10 @@ parseargs(int argc, char *argv[])
>  			break;
>  		case 't':
>  			timeout_sec = atoi(optarg);
> -			timeout = parse_timeout_to_pow2ns(c, NULL, optarg);
> +			timeout = parse_timeout_to_sbt(c, NULL, optarg);
>  			if (debugging)
> -				printf("Timeout is 2^%d nanoseconds\n",
> -				    timeout);
> +				printf("Timeout is %d\n",
> +				    (int)(timeout / SBT_1S));
>  			break;
>  		case 'T':
>  			carp_thresh_seconds =
> @@ -749,7 +698,7 @@ parseargs(int argc, char *argv[])
>  			do_timedog = 1;
>  			break;
>  		case 'x':
> -			exit_timeout = parse_timeout_to_pow2ns(c, NULL, optarg);
> +			exit_timeout = parse_timeout_to_sbt(c, NULL, optarg);
>  			if (exit_timeout != 0)
>  				exit_timeout |= WD_ACTIVE;
>  			break;