]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge git://www.linux-watchdog.org/linux-watchdog
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 20 May 2017 15:35:27 +0000 (08:35 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 20 May 2017 15:35:27 +0000 (08:35 -0700)
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

Documentation/watchdog/watchdog-parameters.txt
drivers/watchdog/Kconfig
drivers/watchdog/bcm_kona_wdt.c
drivers/watchdog/cadence_wdt.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/pcwd_usb.c
drivers/watchdog/sama5d4_wdt.c
drivers/watchdog/wdt_pci.c
drivers/watchdog/zx2967_wdt.c

index 4f7d86dd0a5d88802d85bb68ccf1f93715003a42..914518aeb972872e0fcd3057022d59070c9db282 100644 (file)
@@ -117,7 +117,7 @@ nowayout: Watchdog cannot be stopped once started
 -------------------------------------------------
 iTCO_wdt:
 heartbeat: Watchdog heartbeat in seconds.
-       (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=30)
+       (5<=heartbeat<=74 (TCO v1) or 1226 (TCO v2), default=30)
 nowayout: Watchdog cannot be stopped once started
        (default=kernel config parameter)
 -------------------------------------------------
index 52a70ee6014fa866762042f78b87f3a4c7c7e794..8b9049dac0948db6cc0fca2f25c9f4e5f5cae6bd 100644 (file)
@@ -452,7 +452,7 @@ config DAVINCI_WATCHDOG
 
 config ORION_WATCHDOG
        tristate "Orion watchdog"
-       depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU || COMPILE_TEST
+       depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU || (COMPILE_TEST && !ARCH_EBSA110)
        depends on ARM
        select WATCHDOG_CORE
        help
index 6fce17d5b9f1a27f94e711d0e69d9844c920a91d..a5775dfd8d5fc226e31ca59abb172f504f7efcda 100644 (file)
@@ -304,6 +304,8 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
        if (!wdt)
                return -ENOMEM;
 
+       spin_lock_init(&wdt->lock);
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        wdt->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(wdt->base))
@@ -316,7 +318,6 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
                return ret;
        }
 
-       spin_lock_init(&wdt->lock);
        platform_set_drvdata(pdev, wdt);
        watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt);
        bcm_kona_wdt_wdd.parent = &pdev->dev;
index 8d61e8bfe60b1a418eab489e966652840dedccff..86e0b5d2e7616690007792833e96cc9086ee0144 100644 (file)
@@ -49,7 +49,7 @@
 /* Counter maximum value */
 #define CDNS_WDT_COUNTER_MAX 0xFFF
 
-static int wdt_timeout = CDNS_WDT_DEFAULT_TIMEOUT;
+static int wdt_timeout;
 static int nowayout = WATCHDOG_NOWAYOUT;
 
 module_param(wdt_timeout, int, 0);
index 347f0389b0899d4183021254203e0a0938600267..c4f65873bfa453b1385d2a1371ba10c741df2be9 100644 (file)
@@ -306,16 +306,15 @@ static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
 
        iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout);
 
+       /* Reset the timeout status bit so that the timer
+        * needs to count down twice again before rebooting */
+       outw(0x0008, TCO1_STS(p));      /* write 1 to clear bit */
+
        /* Reload the timer by writing to the TCO Timer Counter register */
-       if (p->iTCO_version >= 2) {
+       if (p->iTCO_version >= 2)
                outw(0x01, TCO_RLD(p));
-       } else if (p->iTCO_version == 1) {
-               /* Reset the timeout status bit so that the timer
-                * needs to count down twice again before rebooting */
-               outw(0x0008, TCO1_STS(p));      /* write 1 to clear bit */
-
+       else if (p->iTCO_version == 1)
                outb(0x01, TCO_RLD(p));
-       }
 
        spin_unlock(&p->io_lock);
        return 0;
@@ -328,11 +327,8 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
        unsigned char val8;
        unsigned int tmrval;
 
-       tmrval = seconds_to_ticks(p, t);
-
-       /* For TCO v1 the timer counts down twice before rebooting */
-       if (p->iTCO_version == 1)
-               tmrval /= 2;
+       /* The timer counts down twice before rebooting */
+       tmrval = seconds_to_ticks(p, t) / 2;
 
        /* from the specs: */
        /* "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)
                spin_lock(&p->io_lock);
                val16 = inw(TCO_RLD(p));
                val16 &= 0x3ff;
+               if (!(inw(TCO1_STS(p)) & 0x0008))
+                       val16 += (inw(TCOv2_TMR(p)) & 0x3ff);
                spin_unlock(&p->io_lock);
 
                time_left = ticks_to_seconds(p, val16);
index 99ebf6ea3de648d881de4ef1f609d1f4d29f5ca0..5615f40139246a19de1be39df6f6ca60b7a705b9 100644 (file)
@@ -630,6 +630,9 @@ static int usb_pcwd_probe(struct usb_interface *interface,
                return -ENODEV;
        }
 
+       if (iface_desc->desc.bNumEndpoints < 1)
+               return -ENODEV;
+
        /* check out the endpoint: it has to be Interrupt & IN */
        endpoint = &iface_desc->endpoint[0].desc;
 
index f709962018ac260107dd2c419c1fbcdfafd4599b..362fd229786df6cea1600108a9060b89b800f475 100644 (file)
@@ -6,6 +6,7 @@
  * Licensed under GPLv2.
  */
 
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -29,6 +30,7 @@ struct sama5d4_wdt {
        struct watchdog_device  wdd;
        void __iomem            *reg_base;
        u32                     mr;
+       unsigned long           last_ping;
 };
 
 static int wdt_timeout = WDT_DEFAULT_TIMEOUT;
@@ -44,11 +46,34 @@ MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+#define wdt_enabled (!(wdt->mr & AT91_WDT_WDDIS))
+
 #define wdt_read(wdt, field) \
        readl_relaxed((wdt)->reg_base + (field))
 
-#define wdt_write(wtd, field, val) \
-       writel_relaxed((val), (wdt)->reg_base + (field))
+/* 4 slow clock periods is 4/32768 = 122.07µs*/
+#define WDT_DELAY      usecs_to_jiffies(123)
+
+static void wdt_write(struct sama5d4_wdt *wdt, u32 field, u32 val)
+{
+       /*
+        * WDT_CR and WDT_MR must not be modified within three slow clock
+        * periods following a restart of the watchdog performed by a write
+        * access in WDT_CR.
+        */
+       while (time_before(jiffies, wdt->last_ping + WDT_DELAY))
+               usleep_range(30, 125);
+       writel_relaxed(val, wdt->reg_base + field);
+       wdt->last_ping = jiffies;
+}
+
+static void wdt_write_nosleep(struct sama5d4_wdt *wdt, u32 field, u32 val)
+{
+       if (time_before(jiffies, wdt->last_ping + WDT_DELAY))
+               udelay(123);
+       writel_relaxed(val, wdt->reg_base + field);
+       wdt->last_ping = jiffies;
+}
 
 static int sama5d4_wdt_start(struct watchdog_device *wdd)
 {
@@ -89,7 +114,16 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
        wdt->mr &= ~AT91_WDT_WDD;
        wdt->mr |= AT91_WDT_SET_WDV(value);
        wdt->mr |= AT91_WDT_SET_WDD(value);
-       wdt_write(wdt, AT91_WDT_MR, wdt->mr);
+
+       /*
+        * WDDIS has to be 0 when updating WDD/WDV. The datasheet states: When
+        * setting the WDDIS bit, and while it is set, the fields WDV and WDD
+        * must not be modified.
+        * If the watchdog is enabled, then the timeout can be updated. Else,
+        * wait that the user enables it.
+        */
+       if (wdt_enabled)
+               wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS);
 
        wdd->timeout = timeout;
 
@@ -145,23 +179,21 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
 
 static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
 {
-       struct watchdog_device *wdd = &wdt->wdd;
-       u32 value = WDT_SEC2TICKS(wdd->timeout);
        u32 reg;
-
        /*
-        * Because the fields WDV and WDD must not be modified when the WDDIS
-        * bit is set, so clear the WDDIS bit before writing the WDT_MR.
+        * When booting and resuming, the bootloader may have changed the
+        * watchdog configuration.
+        * If the watchdog is already running, we can safely update it.
+        * Else, we have to disable it properly.
         */
-       reg = wdt_read(wdt, AT91_WDT_MR);
-       reg &= ~AT91_WDT_WDDIS;
-       wdt_write(wdt, AT91_WDT_MR, reg);
-
-       wdt->mr |= AT91_WDT_SET_WDD(value);
-       wdt->mr |= AT91_WDT_SET_WDV(value);
-
-       wdt_write(wdt, AT91_WDT_MR, wdt->mr);
-
+       if (wdt_enabled) {
+               wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr);
+       } else {
+               reg = wdt_read(wdt, AT91_WDT_MR);
+               if (!(reg & AT91_WDT_WDDIS))
+                       wdt_write_nosleep(wdt, AT91_WDT_MR,
+                                         reg | AT91_WDT_WDDIS);
+       }
        return 0;
 }
 
@@ -172,6 +204,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
        struct resource *res;
        void __iomem *regs;
        u32 irq = 0;
+       u32 timeout;
        int ret;
 
        wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
@@ -184,6 +217,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
        wdd->ops = &sama5d4_wdt_ops;
        wdd->min_timeout = MIN_WDT_TIMEOUT;
        wdd->max_timeout = MAX_WDT_TIMEOUT;
+       wdt->last_ping = jiffies;
 
        watchdog_set_drvdata(wdd, wdt);
 
@@ -221,6 +255,11 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
                return ret;
        }
 
+       timeout = WDT_SEC2TICKS(wdd->timeout);
+
+       wdt->mr |= AT91_WDT_SET_WDD(timeout);
+       wdt->mr |= AT91_WDT_SET_WDV(timeout);
+
        ret = sama5d4_wdt_init(wdt);
        if (ret)
                return ret;
@@ -263,9 +302,7 @@ static int sama5d4_wdt_resume(struct device *dev)
 {
        struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
 
-       wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS);
-       if (wdt->mr & AT91_WDT_WDDIS)
-               wdt_write(wdt, AT91_WDT_MR, wdt->mr);
+       sama5d4_wdt_init(wdt);
 
        return 0;
 }
index 48b2c058b00910ffee5a313812b5cb4d0ee135c5..bc7addc2dc06d0f9ca4bfa09abdbedfb4252090f 100644 (file)
@@ -332,7 +332,7 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
                pr_crit("Would Reboot\n");
 #else
                pr_crit("Initiating system reboot\n");
-               emergency_restart(NULL);
+               emergency_restart();
 #endif
 #else
                pr_crit("Reset in 5ms\n");
index e290d5a13a6d5fa621f650ef03f3b8d7f00f7bb5..c98252733c3069dc5528691cecdee279c8f35c5a 100644 (file)
@@ -211,10 +211,8 @@ static int zx2967_wdt_probe(struct platform_device *pdev)
 
        base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        wdt->reg_base = devm_ioremap_resource(dev, base);
-       if (IS_ERR(wdt->reg_base)) {
-               dev_err(dev, "ioremap failed\n");
+       if (IS_ERR(wdt->reg_base))
                return PTR_ERR(wdt->reg_base);
-       }
 
        zx2967_wdt_reset_sysctrl(dev);