aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2017-04-05 07:41:15 -0400
committerWim Van Sebroeck <wim@iguana.be>2017-05-19 04:42:11 -0400
commit1fccb73011ea8a5fa0c6d357c33fa29c695139ea (patch)
tree4cbf80c4de062175b1835036a5c303022a9ec6be
parent455a9a60b6d4afb293b0e63ec75cc8e82912a767 (diff)
iTCO_wdt: all versions count down twice
The ICH9 is listed as having TCO v2, and indeed the behavior in the datasheet corresponds to v2 (for example the NO_REBOOT flag is accessible via the 16KiB-aligned Root Complex Base Address). However, the TCO counts twice just like in v1; the documentation of the SECOND_TO_STS bit says: "ICH9 sets this bit to 1 to indicate that the TIMEOUT bit had been (or is currently) set and a second timeout occurred before the TCO_RLD register was written. If this bit is set and the NO_REBOOT config bit is 0, then the ICH9 will reboot the system after the second timeout. The same can be found in the BayTrail (Atom E3800) datasheet, and even HOWTOs around the Internet say that it will reboot after _twice_ the specified heartbeat. I did not find the Apollo Lake datasheet, but because v4/v5 has a SECOND_TO_STS bit just like the previous version I'm enabling this for Apollo Lake as well. Cc: linux-watchdog@vger.kernel.org Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--Documentation/watchdog/watchdog-parameters.txt2
-rw-r--r--drivers/watchdog/iTCO_wdt.c22
2 files changed, 11 insertions, 13 deletions
diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt
index 4f7d86dd0a5d..914518aeb972 100644
--- a/Documentation/watchdog/watchdog-parameters.txt
+++ b/Documentation/watchdog/watchdog-parameters.txt
@@ -117,7 +117,7 @@ nowayout: Watchdog cannot be stopped once started
117------------------------------------------------- 117-------------------------------------------------
118iTCO_wdt: 118iTCO_wdt:
119heartbeat: Watchdog heartbeat in seconds. 119heartbeat: Watchdog heartbeat in seconds.
120 (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=30) 120 (5<=heartbeat<=74 (TCO v1) or 1226 (TCO v2), default=30)
121nowayout: Watchdog cannot be stopped once started 121nowayout: Watchdog cannot be stopped once started
122 (default=kernel config parameter) 122 (default=kernel config parameter)
123------------------------------------------------- 123-------------------------------------------------
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 347f0389b089..c4f65873bfa4 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -306,16 +306,15 @@ static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
306 306
307 iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout); 307 iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout);
308 308
309 /* Reset the timeout status bit so that the timer
310 * needs to count down twice again before rebooting */
311 outw(0x0008, TCO1_STS(p)); /* write 1 to clear bit */
312
309 /* Reload the timer by writing to the TCO Timer Counter register */ 313 /* Reload the timer by writing to the TCO Timer Counter register */
310 if (p->iTCO_version >= 2) { 314 if (p->iTCO_version >= 2)
311 outw(0x01, TCO_RLD(p)); 315 outw(0x01, TCO_RLD(p));
312 } else if (p->iTCO_version == 1) { 316 else if (p->iTCO_version == 1)
313 /* Reset the timeout status bit so that the timer
314 * needs to count down twice again before rebooting */
315 outw(0x0008, TCO1_STS(p)); /* write 1 to clear bit */
316
317 outb(0x01, TCO_RLD(p)); 317 outb(0x01, TCO_RLD(p));
318 }
319 318
320 spin_unlock(&p->io_lock); 319 spin_unlock(&p->io_lock);
321 return 0; 320 return 0;
@@ -328,11 +327,8 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
328 unsigned char val8; 327 unsigned char val8;
329 unsigned int tmrval; 328 unsigned int tmrval;
330 329
331 tmrval = seconds_to_ticks(p, t); 330 /* The timer counts down twice before rebooting */
332 331 tmrval = seconds_to_ticks(p, t) / 2;
333 /* For TCO v1 the timer counts down twice before rebooting */
334 if (p->iTCO_version == 1)
335 tmrval /= 2;
336 332
337 /* from the specs: */ 333 /* from the specs: */
338 /* "Values of 0h-3h are ignored and should not be attempted" */ 334 /* "Values of 0h-3h are ignored and should not be attempted" */
@@ -385,6 +381,8 @@ static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
385 spin_lock(&p->io_lock); 381 spin_lock(&p->io_lock);
386 val16 = inw(TCO_RLD(p)); 382 val16 = inw(TCO_RLD(p));
387 val16 &= 0x3ff; 383 val16 &= 0x3ff;
384 if (!(inw(TCO1_STS(p)) & 0x0008))
385 val16 += (inw(TCOv2_TMR(p)) & 0x3ff);
388 spin_unlock(&p->io_lock); 386 spin_unlock(&p->io_lock);
389 387
390 time_left = ticks_to_seconds(p, val16); 388 time_left = ticks_to_seconds(p, val16);