summaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <krzk@kernel.org>2017-02-24 10:11:16 -0500
committerGuenter Roeck <linux@roeck-us.net>2017-02-24 17:00:23 -0500
commit0b445549ea6f91ffea78a976fe89b932db6e077a (patch)
treec93a5baf70597d0adba105b8729394dbd9e4c021 /drivers/watchdog
parent4f21195d42ef930f20e1753532709bb294aa73ac (diff)
watchdog: s3c2410: Fix infinite interrupt in soft mode
In soft (no-reboot) mode, the driver self-pings watchdog upon expiration of an interrupt. However the interrupt itself was not cleared thus on first hit, the system enters infinite interrupt handling loop. On Odroid U3 (Exynos4412), when booted with s3c2410_wdt.soft_noboot=1 argument the console is flooded: # killall -9 watchdog [ 60.523760] s3c2410-wdt 10060000.watchdog: watchdog timer expired (irq) [ 60.536744] s3c2410-wdt 10060000.watchdog: watchdog timer expired (irq) Fix this by writing something to the WTCLRINT register to clear the interrupt. The register WTCLRINT however appeared in S3C6410 so a new watchdog quirk and flavor are needed. Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/s3c2410_wdt.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index b305b8717d9f..558789b8805f 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -46,6 +46,7 @@
46#define S3C2410_WTCON 0x00 46#define S3C2410_WTCON 0x00
47#define S3C2410_WTDAT 0x04 47#define S3C2410_WTDAT 0x04
48#define S3C2410_WTCNT 0x08 48#define S3C2410_WTCNT 0x08
49#define S3C2410_WTCLRINT 0x0c
49 50
50#define S3C2410_WTCNT_MAXCNT 0xffff 51#define S3C2410_WTCNT_MAXCNT 0xffff
51 52
@@ -72,6 +73,7 @@
72#define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c 73#define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c
73#define QUIRK_HAS_PMU_CONFIG (1 << 0) 74#define QUIRK_HAS_PMU_CONFIG (1 << 0)
74#define QUIRK_HAS_RST_STAT (1 << 1) 75#define QUIRK_HAS_RST_STAT (1 << 1)
76#define QUIRK_HAS_WTCLRINT_REG (1 << 2)
75 77
76/* These quirks require that we have a PMU register map */ 78/* These quirks require that we have a PMU register map */
77#define QUIRKS_HAVE_PMUREG (QUIRK_HAS_PMU_CONFIG | \ 79#define QUIRKS_HAVE_PMUREG (QUIRK_HAS_PMU_CONFIG | \
@@ -143,13 +145,18 @@ static const struct s3c2410_wdt_variant drv_data_s3c2410 = {
143}; 145};
144 146
145#ifdef CONFIG_OF 147#ifdef CONFIG_OF
148static const struct s3c2410_wdt_variant drv_data_s3c6410 = {
149 .quirks = QUIRK_HAS_WTCLRINT_REG,
150};
151
146static const struct s3c2410_wdt_variant drv_data_exynos5250 = { 152static const struct s3c2410_wdt_variant drv_data_exynos5250 = {
147 .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, 153 .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
148 .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, 154 .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
149 .mask_bit = 20, 155 .mask_bit = 20,
150 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 156 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
151 .rst_stat_bit = 20, 157 .rst_stat_bit = 20,
152 .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, 158 .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \
159 | QUIRK_HAS_WTCLRINT_REG,
153}; 160};
154 161
155static const struct s3c2410_wdt_variant drv_data_exynos5420 = { 162static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
@@ -158,7 +165,8 @@ static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
158 .mask_bit = 0, 165 .mask_bit = 0,
159 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 166 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
160 .rst_stat_bit = 9, 167 .rst_stat_bit = 9,
161 .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, 168 .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \
169 | QUIRK_HAS_WTCLRINT_REG,
162}; 170};
163 171
164static const struct s3c2410_wdt_variant drv_data_exynos7 = { 172static const struct s3c2410_wdt_variant drv_data_exynos7 = {
@@ -167,12 +175,15 @@ static const struct s3c2410_wdt_variant drv_data_exynos7 = {
167 .mask_bit = 23, 175 .mask_bit = 23,
168 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 176 .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
169 .rst_stat_bit = 23, /* A57 WDTRESET */ 177 .rst_stat_bit = 23, /* A57 WDTRESET */
170 .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, 178 .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \
179 | QUIRK_HAS_WTCLRINT_REG,
171}; 180};
172 181
173static const struct of_device_id s3c2410_wdt_match[] = { 182static const struct of_device_id s3c2410_wdt_match[] = {
174 { .compatible = "samsung,s3c2410-wdt", 183 { .compatible = "samsung,s3c2410-wdt",
175 .data = &drv_data_s3c2410 }, 184 .data = &drv_data_s3c2410 },
185 { .compatible = "samsung,s3c6410-wdt",
186 .data = &drv_data_s3c6410 },
176 { .compatible = "samsung,exynos5250-wdt", 187 { .compatible = "samsung,exynos5250-wdt",
177 .data = &drv_data_exynos5250 }, 188 .data = &drv_data_exynos5250 },
178 { .compatible = "samsung,exynos5420-wdt", 189 { .compatible = "samsung,exynos5420-wdt",
@@ -418,6 +429,10 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
418 dev_info(wdt->dev, "watchdog timer expired (irq)\n"); 429 dev_info(wdt->dev, "watchdog timer expired (irq)\n");
419 430
420 s3c2410wdt_keepalive(&wdt->wdt_device); 431 s3c2410wdt_keepalive(&wdt->wdt_device);
432
433 if (wdt->drv_data->quirks & QUIRK_HAS_WTCLRINT_REG)
434 writel(0x1, wdt->reg_base + S3C2410_WTCLRINT);
435
421 return IRQ_HANDLED; 436 return IRQ_HANDLED;
422} 437}
423 438