Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

watchdog: s3c2410_wdt: Add max and min timeout values

The watchdog maximum timeout value is determined by the number of bits
for the interval timer counter, its source clock frequency, the number
of bits of the prescaler and maximum divider value.

This can be calculated with the following equation:

max_timeout = counter / (freq / (max_prescale + 1) / max_divider)

Setting a maximum timeout value will allow the watchdog core to refuse
user-space calls to the WDIOC_SETTIMEOUT ioctl that sets not supported
timeout values.

For example, systemd tries to set a timeout of 10 minutes on reboot to
ensure that the machine will be rebooted even if a reboot failed. This
leads to the following error message on an Exynos5422 Odroid XU4 board:

[ 147.986045] s3c2410-wdt 101d0000.watchdog: timeout 600 too big

Reported-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

authored by

Javier Martinez Canillas and committed by
Wim Van Sebroeck
882dec1f 57d2caaa

+16
+16
drivers/watchdog/s3c2410_wdt.c
··· 47 47 #define S3C2410_WTDAT 0x04 48 48 #define S3C2410_WTCNT 0x08 49 49 50 + #define S3C2410_WTCNT_MAXCNT 0xffff 51 + 50 52 #define S3C2410_WTCON_RSTEN (1 << 0) 51 53 #define S3C2410_WTCON_INTEN (1 << 2) 52 54 #define S3C2410_WTCON_ENABLE (1 << 5) ··· 58 56 #define S3C2410_WTCON_DIV64 (2 << 3) 59 57 #define S3C2410_WTCON_DIV128 (3 << 3) 60 58 59 + #define S3C2410_WTCON_MAXDIV 0x80 60 + 61 61 #define S3C2410_WTCON_PRESCALE(x) ((x) << 8) 62 62 #define S3C2410_WTCON_PRESCALE_MASK (0xff << 8) 63 + #define S3C2410_WTCON_PRESCALE_MAX 0xff 63 64 64 65 #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) 65 66 #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) ··· 202 197 } while (0) 203 198 204 199 /* functions */ 200 + 201 + static inline unsigned int s3c2410wdt_max_timeout(struct clk *clock) 202 + { 203 + unsigned long freq = clk_get_rate(clock); 204 + 205 + return S3C2410_WTCNT_MAXCNT / (freq / (S3C2410_WTCON_PRESCALE_MAX + 1) 206 + / S3C2410_WTCON_MAXDIV); 207 + } 205 208 206 209 static inline struct s3c2410_wdt *freq_to_wdt(struct notifier_block *nb) 207 210 { ··· 580 567 dev_err(dev, "failed to enable clock\n"); 581 568 return ret; 582 569 } 570 + 571 + wdt->wdt_device.min_timeout = 1; 572 + wdt->wdt_device.max_timeout = s3c2410wdt_max_timeout(wdt->clock); 583 573 584 574 ret = s3c2410wdt_cpufreq_register(wdt); 585 575 if (ret < 0) {