Commit dfb94547 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge git://www.linux-watchdog.org/linux-watchdog

Pull watchdog updates from Wim Van Sebroeck:
 "This contains:
   - addition of the Intel MID watchdog
   - removal of W83697HF and W83697UG drivers (code was merged into
     w83627hf_wdt driver)
   - addition of Armada 375/380 SoC support
   - conversion of imx2_wdt to regmap API and to watchdog core API
   - lots of other small improvements and fixes"

[ Wim was also tagged by gmail as a spammer, but not delayed by days
  unlike Ben ]

* git://www.linux-watchdog.org/linux-watchdog: (25 commits)
  x86: intel-mid: add watchdog platform code for Merrifield
  watchdog: add Intel MID watchdog driver support
  watchdog: sp805: Set watchdog_device->timeout from ->set_timeout()
  booke/watchdog: refine and clean up the codes
  watchdog: iop_wdt only builds for mach-iop13xx
  watchdog: Remove drivers for W83697HF and W83697UG
  watchdog: w83627hf_wdt: Add early_disable module parameter
  ARM: mvebu: Add A375/A380 watchdog binding documentation
  watchdog: orion: Add Armada 375/380 SoC support
  watchdog: orion: Introduce per-SoC enabled() function
  watchdog: orion: Introduce per-SoC stop() function
  watchdog: orion: Remove unneeded atomic access
  watchdog: orion: Introduce a SoC-specific RSTOUT mapping
  watchdog: orion: Move the register ioremap'ing to its own function
  watchdog: xilinx: Make of_device_id array const
  watchdog: imx2_wdt: convert to watchdog core api
  watchdog: imx2_wdt: convert to use regmap API.
  watchdog: imx2_wdt: Sort the header files alphabetically
  watchdog: ath79_wdt: switch to clk_prepare/clk_disable
  watchdog: ath79_wdt: avoid spurious restarts on AR934x
  ...
parents c5aec4c7 78a3bb9e
......@@ -5,11 +5,18 @@ Required Properties:
- Compatibility : "marvell,orion-wdt"
"marvell,armada-370-wdt"
"marvell,armada-xp-wdt"
"marvell,armada-375-wdt"
"marvell,armada-380-wdt"
- reg : Should contain two entries: first one with the
timer control address, second one with the
rstout enable address.
For "marvell,armada-375-wdt" and "marvell,armada-380-wdt":
- reg : A third entry is mandatory and should contain the
shared mask/unmask RSTOUT address.
Optional properties:
- interrupts : Contains the IRQ for watchdog expiration
......
......@@ -728,33 +728,6 @@ static int powerpc_debugfs_init(void)
arch_initcall(powerpc_debugfs_init);
#endif
#ifdef CONFIG_BOOKE_WDT
extern u32 booke_wdt_enabled;
extern u32 booke_wdt_period;
/* Checks wdt=x and wdt_period=xx command-line option */
notrace int __init early_parse_wdt(char *p)
{
if (p && strncmp(p, "0", 1) != 0)
booke_wdt_enabled = 1;
return 0;
}
early_param("wdt", early_parse_wdt);
int __init early_parse_wdt_period(char *p)
{
unsigned long ret;
if (p) {
if (!kstrtol(p, 0, &ret))
booke_wdt_period = ret;
}
return 0;
}
early_param("wdt_period", early_parse_wdt_period);
#endif /* CONFIG_BOOKE_WDT */
void ppc_printk_progress(char *s, unsigned short hex)
{
pr_info("%s\n", s);
......
......@@ -20,3 +20,4 @@ obj-$(subst m,y,$(CONFIG_DRM_MEDFIELD)) += platform_tc35876x.o
obj-$(subst m,y,$(CONFIG_SERIAL_MRST_MAX3110)) += platform_max3111.o
# MISC Devices
obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o
obj-$(subst m,y,$(CONFIG_INTEL_MID_WATCHDOG)) += platform_wdt.o
/*
* platform_wdt.c: Watchdog platform library file
*
* (C) Copyright 2014 Intel Corporation
* Author: David Cohen <david.a.cohen@linux.intel.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/platform_data/intel-mid_wdt.h>
#include <asm/intel-mid.h>
#include <asm/io_apic.h>
#define TANGIER_EXT_TIMER0_MSI 15
static struct platform_device wdt_dev = {
.name = "intel_mid_wdt",
.id = -1,
};
static int tangier_probe(struct platform_device *pdev)
{
int ioapic;
int irq;
struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
struct io_apic_irq_attr irq_attr = { 0 };
if (!pdata)
return -EINVAL;
irq = pdata->irq;
ioapic = mp_find_ioapic(irq);
if (ioapic >= 0) {
int ret;
irq_attr.ioapic = ioapic;
irq_attr.ioapic_pin = irq;
irq_attr.trigger = 1;
/* irq_attr.polarity = 0; -> Active high */
ret = io_apic_set_pci_routing(NULL, irq, &irq_attr);
if (ret)
return ret;
} else {
dev_warn(&pdev->dev, "cannot find interrupt %d in ioapic\n",
irq);
return -EINVAL;
}
return 0;
}
static struct intel_mid_wdt_pdata tangier_pdata = {
.irq = TANGIER_EXT_TIMER0_MSI,
.probe = tangier_probe,
};
static int __init register_mid_wdt(void)
{
if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
wdt_dev.dev.platform_data = &tangier_pdata;
return platform_device_register(&wdt_dev);
}
return -ENODEV;
}
rootfs_initcall(register_mid_wdt);
......@@ -272,7 +272,7 @@ config PNX4008_WATCHDOG
config IOP_WATCHDOG
tristate "IOP Watchdog"
depends on PLAT_IOP
depends on ARCH_IOP13XX
select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
help
Say Y here if to include support for the watchdog timer
......@@ -378,6 +378,8 @@ config MAX63XX_WATCHDOG
config IMX2_WDT
tristate "IMX2+ Watchdog"
depends on ARCH_MXC
select REGMAP_MMIO
select WATCHDOG_CORE
help
This is the driver for the hardware watchdog
on the Freescale IMX2 and later processors.
......@@ -663,6 +665,19 @@ config INTEL_SCU_WATCHDOG
To compile this driver as a module, choose M here.
config INTEL_MID_WATCHDOG
tristate "Intel MID Watchdog Timer"
depends on X86_INTEL_MID
select WATCHDOG_CORE
---help---
Watchdog timer driver built into the Intel SCU for Intel MID
Platforms.
This driver currently supports only the watchdog evolution
implementation in SCU, available for Merrifield generation.
To compile this driver as a module, choose M here.
config ITCO_WDT
tristate "Intel TCO Timer/Watchdog"
depends on (X86 || IA64) && PCI
......@@ -835,7 +850,7 @@ config 60XX_WDT
config SBC8360_WDT
tristate "SBC8360 Watchdog Timer"
depends on X86
depends on X86_32
---help---
This is the driver for the hardware watchdog on the SBC8360 Single
......@@ -938,36 +953,6 @@ config W83627HF_WDT
Most people will say N.
config W83697HF_WDT
tristate "W83697HF/W83697HG Watchdog Timer"
depends on X86
---help---
This is the driver for the hardware watchdog on the W83697HF/HG
chipset as used in Dedibox/VIA motherboards (and likely others).
This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain
amount of time.
To compile this driver as a module, choose M here: the
module will be called w83697hf_wdt.
Most people will say N.
config W83697UG_WDT
tristate "W83697UG/W83697UF Watchdog Timer"
depends on X86
---help---
This is the driver for the hardware watchdog on the W83697UG/UF
chipset as used in MSI Fuzzy CX700 VIA motherboards (and likely others).
This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain
amount of time.
To compile this driver as a module, choose M here: the
module will be called w83697ug_wdt.
Most people will say N.
config W83877F_WDT
tristate "W83877F (EMACS) Watchdog Timer"
depends on X86
......
......@@ -107,13 +107,12 @@ obj-$(CONFIG_SMSC_SCH311X_WDT) += sch311x_wdt.o
obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
obj-$(CONFIG_VIA_WDT) += via_wdt.o
obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
obj-$(CONFIG_W83697UG_WDT) += w83697ug_wdt.o
obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o
# M32R Architecture
......
......@@ -20,6 +20,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/io.h>
......@@ -90,6 +91,15 @@ static inline void ath79_wdt_keepalive(void)
static inline void ath79_wdt_enable(void)
{
ath79_wdt_keepalive();
/*
* Updating the TIMER register requires a few microseconds
* on the AR934x SoCs at least. Use a small delay to ensure
* that the TIMER register is updated within the hardware
* before enabling the watchdog.
*/
udelay(2);
ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR);
/* flush write */
ath79_wdt_rr(WDOG_REG_CTRL);
......@@ -255,7 +265,7 @@ static int ath79_wdt_probe(struct platform_device *pdev)
if (IS_ERR(wdt_clk))
return PTR_ERR(wdt_clk);
err = clk_enable(wdt_clk);
err = clk_prepare_enable(wdt_clk);
if (err)
return err;
......@@ -286,14 +296,14 @@ static int ath79_wdt_probe(struct platform_device *pdev)
return 0;
err_clk_disable:
clk_disable(wdt_clk);
clk_disable_unprepare(wdt_clk);
return err;
}
static int ath79_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&ath79_wdt_miscdev);
clk_disable(wdt_clk);
clk_disable_unprepare(wdt_clk);
return 0;
}
......
......@@ -41,6 +41,28 @@ u32 booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT;
#define WDTP_MASK (TCR_WP_MASK)
#endif
/* Checks wdt=x and wdt_period=xx command-line option */
notrace int __init early_parse_wdt(char *p)
{
if (p && strncmp(p, "0", 1) != 0)
booke_wdt_enabled = 1;
return 0;
}
early_param("wdt", early_parse_wdt);
int __init early_parse_wdt_period(char *p)
{
unsigned long ret;
if (p) {
if (!kstrtol(p, 0, &ret))
booke_wdt_period = ret;
}
return 0;
}
early_param("wdt_period", early_parse_wdt_period);
#ifdef CONFIG_PPC_FSL_BOOK3E
/* For the specified period, determine the number of seconds
......@@ -103,17 +125,18 @@ static unsigned int sec_to_period(unsigned int secs)
static void __booke_wdt_set(void *data)
{
u32 val;
struct watchdog_device *wdog = data;
val = mfspr(SPRN_TCR);
val &= ~WDTP_MASK;
val |= WDTP(booke_wdt_period);
val |= WDTP(sec_to_period(wdog->timeout));
mtspr(SPRN_TCR, val);
}
static void booke_wdt_set(void)
static void booke_wdt_set(void *data)
{
on_each_cpu(__booke_wdt_set, NULL, 0);
on_each_cpu(__booke_wdt_set, data, 0);
}
static void __booke_wdt_ping(void *data)
......@@ -131,12 +154,13 @@ static int booke_wdt_ping(struct watchdog_device *wdog)
static void __booke_wdt_enable(void *data)
{
u32 val;
struct watchdog_device *wdog = data;
/* clear status before enabling watchdog */
__booke_wdt_ping(NULL);
val = mfspr(SPRN_TCR);
val &= ~WDTP_MASK;
val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(sec_to_period(wdog->timeout)));
mtspr(SPRN_TCR, val);
}
......@@ -162,25 +186,17 @@ static void __booke_wdt_disable(void *data)
}
static void __booke_wdt_start(struct watchdog_device *wdog)
static int booke_wdt_start(struct watchdog_device *wdog)
{
on_each_cpu(__booke_wdt_enable, NULL, 0);
on_each_cpu(__booke_wdt_enable, wdog, 0);
pr_debug("watchdog enabled (timeout = %u sec)\n", wdog->timeout);
}
static int booke_wdt_start(struct watchdog_device *wdog)
{
if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1;
__booke_wdt_start(wdog);
}
return 0;
}
static int booke_wdt_stop(struct watchdog_device *wdog)
{
on_each_cpu(__booke_wdt_disable, NULL, 0);
booke_wdt_enabled = 0;
pr_debug("watchdog disabled\n");
return 0;
......@@ -191,9 +207,8 @@ static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev,
{
if (timeout > MAX_WDT_TIMEOUT)
return -EINVAL;
booke_wdt_period = sec_to_period(timeout);
wdt_dev->timeout = timeout;
booke_wdt_set();
booke_wdt_set(wdt_dev);
return 0;
}
......@@ -231,10 +246,10 @@ static int __init booke_wdt_init(void)
pr_info("powerpc book-e watchdog driver loaded\n");
booke_wdt_info.firmware_version = cur_cpu_spec->pvr_value;
booke_wdt_set_timeout(&booke_wdt_dev,
period_to_sec(CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT));
period_to_sec(booke_wdt_period));
watchdog_set_nowayout(&booke_wdt_dev, nowayout);
if (booke_wdt_enabled)
__booke_wdt_start(&booke_wdt_dev);
booke_wdt_start(&booke_wdt_dev);
ret = watchdog_register_device(&booke_wdt_dev);
......
......@@ -21,19 +21,17 @@
* Halt on suspend: Manual Can be automatic
*/
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#include <linux/clk.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/regmap.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/watchdog.h>
#define DRIVER_NAME "imx2-wdt"
......@@ -55,19 +53,12 @@
#define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
#define IMX2_WDT_STATUS_OPEN 0
#define IMX2_WDT_STATUS_STARTED 1
#define IMX2_WDT_EXPECT_CLOSE 2
static struct {
struct imx2_wdt_device {
struct clk *clk;
void __iomem *base;
unsigned timeout;
unsigned long status;
struct regmap *regmap;
struct timer_list timer; /* Pings the watchdog when closed */
} imx2_wdt;
static struct miscdevice imx2_wdt_miscdev;
struct watchdog_device wdog;
};
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
......@@ -85,9 +76,12 @@ static const struct watchdog_info imx2_wdt_info = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
};
static inline void imx2_wdt_setup(void)
static inline void imx2_wdt_setup(struct watchdog_device *wdog)
{
u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR);
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
u32 val;
regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
/* Suspend timer in low power mode, write once-only */
val |= IMX2_WDT_WCR_WDZST;
......@@ -98,227 +92,199 @@ static inline void imx2_wdt_setup(void)
/* Keep Watchdog Disabled */
val &= ~IMX2_WDT_WCR_WDE;
/* Set the watchdog's Time-Out value */
val |= WDOG_SEC_TO_COUNT(imx2_wdt.timeout);
val |= WDOG_SEC_TO_COUNT(wdog->timeout);
__raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
/* enable the watchdog */
val |= IMX2_WDT_WCR_WDE;
__raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
}
static inline void imx2_wdt_ping(void)
static inline bool imx2_wdt_is_running(struct imx2_wdt_device *wdev)
{
__raw_writew(IMX2_WDT_SEQ1, imx2_wdt.base + IMX2_WDT_WSR);
__raw_writew(IMX2_WDT_SEQ2, imx2_wdt.base + IMX2_WDT_WSR);
}
u32 val;
static void imx2_wdt_timer_ping(unsigned long arg)
{
/* ping it every imx2_wdt.timeout / 2 seconds to prevent reboot */
imx2_wdt_ping();
mod_timer(&imx2_wdt.timer, jiffies + imx2_wdt.timeout * HZ / 2);
regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
return val & IMX2_WDT_WCR_WDE;
}
static void imx2_wdt_start(void)
static int imx2_wdt_ping(struct watchdog_device *wdog)
{
if (!test_and_set_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) {
/* at our first start we enable clock and do initialisations */
clk_prepare_enable(imx2_wdt.clk);
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
imx2_wdt_setup();
} else /* delete the timer that pings the watchdog after close */
del_timer_sync(&imx2_wdt.timer);
/* Watchdog is enabled - time to reload the timeout value */
imx2_wdt_ping();
regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
return 0;
}
static void imx2_wdt_stop(void)
static void imx2_wdt_timer_ping(unsigned long arg)
{
/* we don't need a clk_disable, it cannot be disabled once started.
* We use a timer to ping the watchdog while /dev/watchdog is closed */
imx2_wdt_timer_ping(0);
struct watchdog_device *wdog = (struct watchdog_device *)arg;
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
/* ping it every wdog->timeout / 2 seconds to prevent reboot */
imx2_wdt_ping(wdog);
mod_timer(&wdev->timer, jiffies + wdog->timeout * HZ / 2);
}
static void imx2_wdt_set_timeout(int new_timeout)
static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
unsigned int new_timeout)
{
u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR);
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
/* set the new timeout value in the WSR */
val &= ~IMX2_WDT_WCR_WT;
val |= WDOG_SEC_TO_COUNT(new_timeout);
__raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
WDOG_SEC_TO_COUNT(new_timeout));
return 0;
}
static int imx2_wdt_open(struct inode *inode, struct file *file)
static int imx2_wdt_start(struct watchdog_device *wdog)
{
if (test_and_set_bit(IMX2_WDT_STATUS_OPEN, &imx2_wdt.status))
return -EBUSY;
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
if (imx2_wdt_is_running(wdev)) {
/* delete the timer that pings the watchdog after close */
del_timer_sync(&wdev->timer);
imx2_wdt_set_timeout(wdog, wdog->timeout);
} else
imx2_wdt_setup(wdog);
imx2_wdt_start();
return nonseekable_open(inode, file);
return imx2_wdt_ping(wdog);
}
static int imx2_wdt_close(struct inode *inode, struct file *file)
static int imx2_wdt_stop(struct watchdog_device *wdog)
{
if (test_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status) && !nowayout)
imx2_wdt_stop();
else {
dev_crit(imx2_wdt_miscdev.parent,
"Unexpected close: Expect reboot!\n");
imx2_wdt_ping();
}
clear_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
clear_bit(IMX2_WDT_STATUS_OPEN, &imx2_wdt.status);
/*
* We don't need a clk_disable, it cannot be disabled once started.
* We use a timer to ping the watchdog while /dev/watchdog is closed
*/
imx2_wdt_timer_ping((unsigned long)wdog);
return 0;
}
static long imx2_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
static inline void imx2_wdt_ping_if_active(struct watchdog_device *wdog)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_value;
u16 val;
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &imx2_wdt_info,
sizeof(struct watchdog_info)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
return put_user(0, p);
case WDIOC_GETBOOTSTATUS:
val = __raw_readw(imx2_wdt.base + IMX2_WDT_WRSR);
new_value = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
return put_user(new_value, p);
case WDIOC_KEEPALIVE:
imx2_wdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_value, p))
return -EFAULT;
if ((new_value < 1) || (new_value > IMX2_WDT_MAX_TIME))
return -EINVAL;
imx2_wdt_set_timeout(new_value);
imx2_wdt.timeout = new_value;
imx2_wdt_ping();
/* Fallthrough to return current value */
case WDIOC_GETTIMEOUT:
return put_user(imx2_wdt.timeout, p);
default:
return -ENOTTY;