amdsbwd: fix handling of timeout values beyond the supported range

The driver now fully observes watchdog(9) protocol.
Previously a too large timeout was silently clamped while the correct
behavior is to disable the watchdog and leave the error as is
(i.e. to not report success).

Also, previously a too small value caused the timer to stop while the
correct behavior is to use the minimal supported value.

MFC after:	2 weeks
This commit is contained in:
Andriy Gapon 2018-01-10 17:35:00 +00:00
parent a333cdf369
commit cf38c8c630
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=327775

View File

@ -210,21 +210,30 @@ static void
amdsbwd_event(void *arg, unsigned int cmd, int *error)
{
struct amdsbwd_softc *sc = arg;
unsigned int timeout;
uint64_t timeout;
/* convert from power-of-two-ns to WDT ticks */
cmd &= WD_INTERVAL;
if (cmd < WD_TO_1SEC)
cmd = 0;
if (cmd) {
timeout = ((uint64_t)1 << (cmd - WD_TO_1MS)) / sc->ms_per_tick;
if (timeout > sc->max_ticks)
timeout = sc->max_ticks;
if (timeout != sc->timeout) {
amdsbwd_tmr_set(sc, timeout);
if (!sc->active)
amdsbwd_tmr_enable(sc);
if (cmd != 0) {
timeout = 0;
cmd &= WD_INTERVAL;
if (cmd >= WD_TO_1MS) {
timeout = (uint64_t)1 << (cmd - WD_TO_1MS);
timeout = timeout / sc->ms_per_tick;
}
/* For a too short timeout use 1 tick. */
if (timeout == 0)
timeout = 1;
/* For a too long timeout stop the timer. */
if (timeout > sc->max_ticks)
timeout = 0;
} else {
timeout = 0;
}
if (timeout != 0) {
if (timeout != sc->timeout)
amdsbwd_tmr_set(sc, timeout);
if (!sc->active)
amdsbwd_tmr_enable(sc);
amdsbwd_tmr_reload(sc);
*error = 0;
} else {