forked from Minki/linux
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
This commit is contained in:
commit
ec53c027f3
@ -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)
|
||||
-------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -306,16 +306,15 @@ static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
|
||||
|
||||
iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout);
|
||||
|
||||
/* Reload the timer by writing to the TCO Timer Counter register */
|
||||
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 */
|
||||
/* 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)
|
||||
outw(0x01, TCO_RLD(p));
|
||||
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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user