aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-20 11:35:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-20 11:35:27 -0400
commitec53c027f3e6b0ee82a5d18de7b0d8bfae3ec374 (patch)
treeaacd536cf8c7562c8a0464821cd3e53c4ce27399
parentcf80a6fbca377516628ea50507eded0a51e88d8c (diff)
parentfedf266f9955d9a019643cde199a2fd9a0259f6f (diff)
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog fixes from Wim Van Sebroeck: - orion_wdt compile-test dependencies - sama5d4_wdt: WDDIS handling and a race confition - pcwd_usb: fix NULL-deref at probe - cadence_wdt: fix timeout setting - wdt_pci: fix build error if SOFTWARE_REBOOT is defined - iTCO_wdt: all versions count down twice - zx2967: remove redundant dev_err call in zx2967_wdt_probe() - bcm281xx: Fix use of uninitialized spinlock * git://www.linux-watchdog.org/linux-watchdog: watchdog: bcm281xx: Fix use of uninitialized spinlock. watchdog: zx2967: remove redundant dev_err call in zx2967_wdt_probe() iTCO_wdt: all versions count down twice watchdog: wdt_pci: fix build error if define SOFTWARE_REBOOT watchdog: cadence_wdt: fix timeout setting watchdog: pcwd_usb: fix NULL-deref at probe watchdog: sama5d4: fix race condition watchdog: sama5d4: fix WDDIS handling watchdog: orion: fix compile-test dependencies
-rw-r--r--Documentation/watchdog/watchdog-parameters.txt2
-rw-r--r--drivers/watchdog/Kconfig2
-rw-r--r--drivers/watchdog/bcm_kona_wdt.c3
-rw-r--r--drivers/watchdog/cadence_wdt.c2
-rw-r--r--drivers/watchdog/iTCO_wdt.c22
-rw-r--r--drivers/watchdog/pcwd_usb.c3
-rw-r--r--drivers/watchdog/sama5d4_wdt.c77
-rw-r--r--drivers/watchdog/wdt_pci.c2
-rw-r--r--drivers/watchdog/zx2967_wdt.c4
9 files changed, 77 insertions, 40 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/Kconfig b/drivers/watchdog/Kconfig
index 52a70ee6014f..8b9049dac094 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -452,7 +452,7 @@ config DAVINCI_WATCHDOG
452 452
453config ORION_WATCHDOG 453config ORION_WATCHDOG
454 tristate "Orion watchdog" 454 tristate "Orion watchdog"
455 depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU || COMPILE_TEST 455 depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU || (COMPILE_TEST && !ARCH_EBSA110)
456 depends on ARM 456 depends on ARM
457 select WATCHDOG_CORE 457 select WATCHDOG_CORE
458 help 458 help
diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c
index 6fce17d5b9f1..a5775dfd8d5f 100644
--- a/drivers/watchdog/bcm_kona_wdt.c
+++ b/drivers/watchdog/bcm_kona_wdt.c
@@ -304,6 +304,8 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
304 if (!wdt) 304 if (!wdt)
305 return -ENOMEM; 305 return -ENOMEM;
306 306
307 spin_lock_init(&wdt->lock);
308
307 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 309 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
308 wdt->base = devm_ioremap_resource(dev, res); 310 wdt->base = devm_ioremap_resource(dev, res);
309 if (IS_ERR(wdt->base)) 311 if (IS_ERR(wdt->base))
@@ -316,7 +318,6 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
316 return ret; 318 return ret;
317 } 319 }
318 320
319 spin_lock_init(&wdt->lock);
320 platform_set_drvdata(pdev, wdt); 321 platform_set_drvdata(pdev, wdt);
321 watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt); 322 watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt);
322 bcm_kona_wdt_wdd.parent = &pdev->dev; 323 bcm_kona_wdt_wdd.parent = &pdev->dev;
diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c
index 8d61e8bfe60b..86e0b5d2e761 100644
--- a/drivers/watchdog/cadence_wdt.c
+++ b/drivers/watchdog/cadence_wdt.c
@@ -49,7 +49,7 @@
49/* Counter maximum value */ 49/* Counter maximum value */
50#define CDNS_WDT_COUNTER_MAX 0xFFF 50#define CDNS_WDT_COUNTER_MAX 0xFFF
51 51
52static int wdt_timeout = CDNS_WDT_DEFAULT_TIMEOUT; 52static int wdt_timeout;
53static int nowayout = WATCHDOG_NOWAYOUT; 53static int nowayout = WATCHDOG_NOWAYOUT;
54 54
55module_param(wdt_timeout, int, 0); 55module_param(wdt_timeout, int, 0);
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);
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
index 99ebf6ea3de6..5615f4013924 100644
--- a/drivers/watchdog/pcwd_usb.c
+++ b/drivers/watchdog/pcwd_usb.c
@@ -630,6 +630,9 @@ static int usb_pcwd_probe(struct usb_interface *interface,
630 return -ENODEV; 630 return -ENODEV;
631 } 631 }
632 632
633 if (iface_desc->desc.bNumEndpoints < 1)
634 return -ENODEV;
635
633 /* check out the endpoint: it has to be Interrupt & IN */ 636 /* check out the endpoint: it has to be Interrupt & IN */
634 endpoint = &iface_desc->endpoint[0].desc; 637 endpoint = &iface_desc->endpoint[0].desc;
635 638
diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c
index f709962018ac..362fd229786d 100644
--- a/drivers/watchdog/sama5d4_wdt.c
+++ b/drivers/watchdog/sama5d4_wdt.c
@@ -6,6 +6,7 @@
6 * Licensed under GPLv2. 6 * Licensed under GPLv2.
7 */ 7 */
8 8
9#include <linux/delay.h>
9#include <linux/interrupt.h> 10#include <linux/interrupt.h>
10#include <linux/io.h> 11#include <linux/io.h>
11#include <linux/kernel.h> 12#include <linux/kernel.h>
@@ -29,6 +30,7 @@ struct sama5d4_wdt {
29 struct watchdog_device wdd; 30 struct watchdog_device wdd;
30 void __iomem *reg_base; 31 void __iomem *reg_base;
31 u32 mr; 32 u32 mr;
33 unsigned long last_ping;
32}; 34};
33 35
34static int wdt_timeout = WDT_DEFAULT_TIMEOUT; 36static int wdt_timeout = WDT_DEFAULT_TIMEOUT;
@@ -44,11 +46,34 @@ MODULE_PARM_DESC(nowayout,
44 "Watchdog cannot be stopped once started (default=" 46 "Watchdog cannot be stopped once started (default="
45 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 47 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
46 48
49#define wdt_enabled (!(wdt->mr & AT91_WDT_WDDIS))
50
47#define wdt_read(wdt, field) \ 51#define wdt_read(wdt, field) \
48 readl_relaxed((wdt)->reg_base + (field)) 52 readl_relaxed((wdt)->reg_base + (field))
49 53
50#define wdt_write(wtd, field, val) \ 54/* 4 slow clock periods is 4/32768 = 122.07µs*/
51 writel_relaxed((val), (wdt)->reg_base + (field)) 55#define WDT_DELAY usecs_to_jiffies(123)
56
57static void wdt_write(struct sama5d4_wdt *wdt, u32 field, u32 val)
58{
59 /*
60 * WDT_CR and WDT_MR must not be modified within three slow clock
61 * periods following a restart of the watchdog performed by a write
62 * access in WDT_CR.
63 */
64 while (time_before(jiffies, wdt->last_ping + WDT_DELAY))
65 usleep_range(30, 125);
66 writel_relaxed(val, wdt->reg_base + field);
67 wdt->last_ping = jiffies;
68}
69
70static void wdt_write_nosleep(struct sama5d4_wdt *wdt, u32 field, u32 val)
71{
72 if (time_before(jiffies, wdt->last_ping + WDT_DELAY))
73 udelay(123);
74 writel_relaxed(val, wdt->reg_base + field);
75 wdt->last_ping = jiffies;
76}
52 77
53static int sama5d4_wdt_start(struct watchdog_device *wdd) 78static int sama5d4_wdt_start(struct watchdog_device *wdd)
54{ 79{
@@ -89,7 +114,16 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
89 wdt->mr &= ~AT91_WDT_WDD; 114 wdt->mr &= ~AT91_WDT_WDD;
90 wdt->mr |= AT91_WDT_SET_WDV(value); 115 wdt->mr |= AT91_WDT_SET_WDV(value);
91 wdt->mr |= AT91_WDT_SET_WDD(value); 116 wdt->mr |= AT91_WDT_SET_WDD(value);
92 wdt_write(wdt, AT91_WDT_MR, wdt->mr); 117
118 /*
119 * WDDIS has to be 0 when updating WDD/WDV. The datasheet states: When
120 * setting the WDDIS bit, and while it is set, the fields WDV and WDD
121 * must not be modified.
122 * If the watchdog is enabled, then the timeout can be updated. Else,
123 * wait that the user enables it.
124 */
125 if (wdt_enabled)
126 wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS);
93 127
94 wdd->timeout = timeout; 128 wdd->timeout = timeout;
95 129
@@ -145,23 +179,21 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
145 179
146static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) 180static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
147{ 181{
148 struct watchdog_device *wdd = &wdt->wdd;
149 u32 value = WDT_SEC2TICKS(wdd->timeout);
150 u32 reg; 182 u32 reg;
151
152 /* 183 /*
153 * Because the fields WDV and WDD must not be modified when the WDDIS 184 * When booting and resuming, the bootloader may have changed the
154 * bit is set, so clear the WDDIS bit before writing the WDT_MR. 185 * watchdog configuration.
186 * If the watchdog is already running, we can safely update it.
187 * Else, we have to disable it properly.
155 */ 188 */
156 reg = wdt_read(wdt, AT91_WDT_MR); 189 if (wdt_enabled) {
157 reg &= ~AT91_WDT_WDDIS; 190 wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr);
158 wdt_write(wdt, AT91_WDT_MR, reg); 191 } else {
159 192 reg = wdt_read(wdt, AT91_WDT_MR);
160 wdt->mr |= AT91_WDT_SET_WDD(value); 193 if (!(reg & AT91_WDT_WDDIS))
161 wdt->mr |= AT91_WDT_SET_WDV(value); 194 wdt_write_nosleep(wdt, AT91_WDT_MR,
162 195 reg | AT91_WDT_WDDIS);
163 wdt_write(wdt, AT91_WDT_MR, wdt->mr); 196 }
164
165 return 0; 197 return 0;
166} 198}
167 199
@@ -172,6 +204,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
172 struct resource *res; 204 struct resource *res;
173 void __iomem *regs; 205 void __iomem *regs;
174 u32 irq = 0; 206 u32 irq = 0;
207 u32 timeout;
175 int ret; 208 int ret;
176 209
177 wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); 210 wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
@@ -184,6 +217,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
184 wdd->ops = &sama5d4_wdt_ops; 217 wdd->ops = &sama5d4_wdt_ops;
185 wdd->min_timeout = MIN_WDT_TIMEOUT; 218 wdd->min_timeout = MIN_WDT_TIMEOUT;
186 wdd->max_timeout = MAX_WDT_TIMEOUT; 219 wdd->max_timeout = MAX_WDT_TIMEOUT;
220 wdt->last_ping = jiffies;
187 221
188 watchdog_set_drvdata(wdd, wdt); 222 watchdog_set_drvdata(wdd, wdt);
189 223
@@ -221,6 +255,11 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
221 return ret; 255 return ret;
222 } 256 }
223 257
258 timeout = WDT_SEC2TICKS(wdd->timeout);
259
260 wdt->mr |= AT91_WDT_SET_WDD(timeout);
261 wdt->mr |= AT91_WDT_SET_WDV(timeout);
262
224 ret = sama5d4_wdt_init(wdt); 263 ret = sama5d4_wdt_init(wdt);
225 if (ret) 264 if (ret)
226 return ret; 265 return ret;
@@ -263,9 +302,7 @@ static int sama5d4_wdt_resume(struct device *dev)
263{ 302{
264 struct sama5d4_wdt *wdt = dev_get_drvdata(dev); 303 struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
265 304
266 wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS); 305 sama5d4_wdt_init(wdt);
267 if (wdt->mr & AT91_WDT_WDDIS)
268 wdt_write(wdt, AT91_WDT_MR, wdt->mr);
269 306
270 return 0; 307 return 0;
271} 308}
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index 48b2c058b009..bc7addc2dc06 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -332,7 +332,7 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
332 pr_crit("Would Reboot\n"); 332 pr_crit("Would Reboot\n");
333#else 333#else
334 pr_crit("Initiating system reboot\n"); 334 pr_crit("Initiating system reboot\n");
335 emergency_restart(NULL); 335 emergency_restart();
336#endif 336#endif
337#else 337#else
338 pr_crit("Reset in 5ms\n"); 338 pr_crit("Reset in 5ms\n");
diff --git a/drivers/watchdog/zx2967_wdt.c b/drivers/watchdog/zx2967_wdt.c
index e290d5a13a6d..c98252733c30 100644
--- a/drivers/watchdog/zx2967_wdt.c
+++ b/drivers/watchdog/zx2967_wdt.c
@@ -211,10 +211,8 @@ static int zx2967_wdt_probe(struct platform_device *pdev)
211 211
212 base = platform_get_resource(pdev, IORESOURCE_MEM, 0); 212 base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
213 wdt->reg_base = devm_ioremap_resource(dev, base); 213 wdt->reg_base = devm_ioremap_resource(dev, base);
214 if (IS_ERR(wdt->reg_base)) { 214 if (IS_ERR(wdt->reg_base))
215 dev_err(dev, "ioremap failed\n");
216 return PTR_ERR(wdt->reg_base); 215 return PTR_ERR(wdt->reg_base);
217 }
218 216
219 zx2967_wdt_reset_sysctrl(dev); 217 zx2967_wdt_reset_sysctrl(dev);
220 218