Commit 7e6127c1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'linux-watchdog-4.16-rc1' of git://www.linux-watchdog.org/linux-watchdog

Pull watchdog updates from Wim Van Sebroeck:

 - new watchdog device drivers for Realtek RTD1295 and Spreadtrum SC9860
   platform

 - add support for the following devices: jz4780 SoC, AST25xx series SoC
   and r8a77970 SoC

 - convert to watchdog framework: i6300esb_wdt, xen_wdt and sp5100_tco

 - several fixes for watchdog core

 - remove at32ap700x and obsolete documentation

 - gpio: Convert to use GPIO descriptors

 - rename gemini into FTWDT010 as this IP block is generc from Faraday
   Technology

 - various clean-ups and small bugfixes

 - add Guenter Roeck as co-maintainer

 - change maintainers e-mail address

* tag 'linux-watchdog-4.16-rc1' of git://www.linux-watchdog.org/linux-watchdog: (74 commits)
  documentation: watchdog: remove documentation of w83697hf_wdt/w83697ug_wdt
  documentation: watchdog: remove documentation for ixp2000
  documentation: watchdog: remove documentation of at32ap700x_wdt
  watchdog: remove at32ap700x_wdt
  watchdog: sp5100_tco: Add support for recent FCH versions
  watchdog: sp5100-tco: Abort if watchdog is disabled by hardware
  watchdog: sp5100_tco: Use bit operations
  watchdog: sp5100_tco: Convert to use watchdog subsystem
  watchdog: sp5100_tco: Clean up function and variable names
  watchdog: sp5100_tco: Use dev_ print functions where possible
  watchdog: sp5100_tco: Match PCI device early
  watchdog: sp5100_tco: Clean up sp5100_tco_setupdevice
  watchdog: sp5100_tco: Use standard error codes
  watchdog: sp5100_tco: Use request_muxed_region where possible
  watchdog: sp5100_tco: Fix watchdog disable bit
  watchdog: sp5100_tco: Always use SP5100_IO_PM_{INDEX_REG,DATA_REG}
  watchdog: core: make sure the watchdog_worker is not deferred
  watchdog: mt7621: switch to using managed devm_watchdog_register_device()
  watchdog: mt7621: set WDOG_HW_RUNNING bit when appropriate
  watchdog: imx2_wdt: restore previous timeout after suspend+resume
  ...
parents 413879a1 592a547a
Cortina Systems Gemini SoC Watchdog
Required properties:
- compatible : must be "cortina,gemini-watchdog"
- reg : shall contain base register location and length
- interrupts : shall contain the interrupt for the watchdog
Optional properties:
- timeout-sec : the default watchdog timeout in seconds.
Example:
watchdog@41000000 {
compatible = "cortina,gemini-watchdog";
reg = <0x41000000 0x1000>;
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
};
Cortina Systems Gemini SoC Watchdog
Faraday Technology FTWDT010 watchdog
This is an IP part from Faraday Technology found in the Gemini
SoCs and others.
Required properties:
- compatible : must be "cortina,gemini-watchdog"
- compatible : must be one of
"faraday,ftwdt010"
"cortina,gemini-watchdog", "faraday,ftwdt010"
- reg : shall contain base register location and length
- interrupts : shall contain the interrupt for the watchdog
......@@ -11,7 +16,7 @@ Optional properties:
Example:
watchdog@41000000 {
compatible = "cortina,gemini-watchdog";
compatible = "faraday,ftwdt010";
reg = <0x41000000 0x1000>;
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
};
Ingenic Watchdog Timer (WDT) Controller for JZ4740
Ingenic Watchdog Timer (WDT) Controller for JZ4740 & JZ4780
Required properties:
compatible: "ingenic,jz4740-watchdog"
compatible: "ingenic,jz4740-watchdog" or "ingenic,jz4780-watchdog"
reg: Register address and length for watchdog registers
Example:
......
Realtek RTD1295 Watchdog
========================
Required properties:
- compatible : Should be "realtek,rtd1295-watchdog"
- reg : Specifies the physical base address and size of registers
- clocks : Specifies one clock input
Example:
watchdog@98007680 {
compatible = "realtek,rtd1295-watchdog";
reg = <0x98007680 0x100>;
clocks = <&osc27M>;
};
......@@ -4,10 +4,11 @@ Required properties:
- compatible : Should be "renesas,<soctype>-wdt", and
"renesas,rcar-gen3-wdt" or "renesas,rza-wdt" as fallback.
Examples with soctypes are:
- "renesas,r7s72100-wdt" (RZ/A1)
- "renesas,r8a7795-wdt" (R-Car H3)
- "renesas,r8a7796-wdt" (R-Car M3-W)
- "renesas,r8a77970-wdt" (R-Car V3M)
- "renesas,r8a77995-wdt" (R-Car D3)
- "renesas,r7s72100-wdt" (RZ/A1)
When compatible with the generic version, nodes must list the SoC-specific
version corresponding to the platform first, followed by the generic
......
Spreadtrum SoCs Watchdog timer
Required properties:
- compatible : Should be "sprd,sp9860-wdt".
- reg : Specifies base physical address and size of the registers.
- interrupts : Exactly one interrupt specifier.
- timeout-sec : Contain the default watchdog timeout in seconds.
- clock-names : Contain the input clock names.
- clocks : Phandles to input clocks.
Example:
watchdog: watchdog@40310000 {
compatible = "sprd,sp9860-wdt";
reg = <0 0x40310000 0 0x1000>;
interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
timeout-sec = <12>;
clock-names = "enable", "rtc_enable";
clocks = <&clk_aon_apb_gates1 8>, <&clk_aon_apb_rtc_gates 9>;
};
......@@ -40,11 +40,6 @@ margin: Watchdog margin in seconds (default=60)
nowayout: Disable watchdog shutdown on close
(default=kernel config parameter)
-------------------------------------------------
at32ap700x_wdt:
timeout: Timeout value. Limited to be 1 or 2 seconds. (default=2)
nowayout: Watchdog cannot be stopped once started
(default=kernel config parameter)
-------------------------------------------------
at91rm9200_wdt:
wdt_time: Watchdog time in seconds. (default=5)
nowayout: Watchdog cannot be stopped once started
......@@ -162,11 +157,6 @@ testmode: Watchdog test mode (1 = no reboot), default=0
nowayout: Watchdog cannot be stopped once started
(default=kernel config parameter)
-------------------------------------------------
ixp2000_wdt:
heartbeat: Watchdog heartbeat in seconds (default 60s)
nowayout: Watchdog cannot be stopped once started
(default=kernel config parameter)
-------------------------------------------------
ixp4xx_wdt:
heartbeat: Watchdog heartbeat in seconds (default 60s)
nowayout: Watchdog cannot be stopped once started
......@@ -381,19 +371,6 @@ timeout: Watchdog timeout in seconds. 1 <= timeout <= 255, default=60.
nowayout: Watchdog cannot be stopped once started
(default=kernel config parameter)
-------------------------------------------------
w83697hf_wdt:
wdt_io: w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)
timeout: Watchdog timeout in seconds. 1<= timeout <=255 (default=60)
nowayout: Watchdog cannot be stopped once started
(default=kernel config parameter)
early_disable: Watchdog gets disabled at boot time (default=1)
-------------------------------------------------
w83697ug_wdt:
wdt_io: w83697ug/uf WDT io port (default 0x2e)
timeout: Watchdog timeout in seconds. 1<= timeout <=255 (default=60)
nowayout: Watchdog cannot be stopped once started
(default=kernel config parameter)
-------------------------------------------------
w83877f_wdt:
timeout: Watchdog timeout in seconds. (1<=timeout<=3600, default=30)
nowayout: Watchdog cannot be stopped once started
......
......@@ -14991,8 +14991,8 @@ S: Maintained
F: drivers/input/tablet/wacom_serial4.c
WATCHDOG DEVICE DRIVERS
M: Wim Van Sebroeck <wim@iguana.be>
R: Guenter Roeck <linux@roeck-us.net>
M: Wim Van Sebroeck <wim@linux-watchdog.org>
M: Guenter Roeck <linux@roeck-us.net>
L: linux-watchdog@vger.kernel.org
W: http://www.linux-watchdog.org/
T: git git://www.linux-watchdog.org/linux-watchdog.git
......
......@@ -328,16 +328,18 @@ config 977_WATCHDOG
Not sure? It's safe to say N.
config GEMINI_WATCHDOG
tristate "Gemini watchdog"
depends on ARCH_GEMINI
config FTWDT010_WATCHDOG
tristate "Faraday Technology FTWDT010 watchdog"
depends on ARM || COMPILE_TEST
select WATCHDOG_CORE
default ARCH_GEMINI
help
Say Y here if to include support for the watchdog timer
embedded in the Cortina Systems Gemini family of devices.
Say Y here if to include support for the Faraday Technology
FTWDT010 watchdog timer embedded in the Cortina Systems Gemini
family of devices.
To compile this driver as a module, choose M here: the
module will be called gemini_wdt.
module will be called ftwdt010_wdt.
config IXP4XX_WATCHDOG
tristate "IXP4xx Watchdog"
......@@ -748,12 +750,12 @@ config RENESAS_RZAWDT
Renesas RZ/A SoCs. These watchdogs can be used to reset a system.
config ASPEED_WATCHDOG
tristate "Aspeed 2400 watchdog support"
tristate "Aspeed BMC watchdog support"
depends on ARCH_ASPEED || COMPILE_TEST
select WATCHDOG_CORE
help
Say Y here to include support for the watchdog timer
in Apseed BMC SoCs.
in Aspeed BMC SoCs.
This driver is required to reboot the SoC.
......@@ -794,14 +796,23 @@ config UNIPHIER_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called uniphier_wdt.
# AVR32 Architecture
config RTD119X_WATCHDOG
bool "Realtek RTD119x/RTD129x watchdog support"
depends on ARCH_REALTEK || COMPILE_TEST
depends on OF
select WATCHDOG_CORE
default ARCH_REALTEK
help
Say Y here to include support for the watchdog timer in
Realtek RTD1295 SoCs.
config AT32AP700X_WDT
tristate "AT32AP700x watchdog"
depends on CPU_AT32AP700X || COMPILE_TEST
config SPRD_WATCHDOG
tristate "Spreadtrum watchdog support"
depends on ARCH_SPRD || COMPILE_TEST
select WATCHDOG_CORE
help
Watchdog timer embedded into AT32AP700x devices. This will reboot
your system when the timeout is reached.
Say Y here to include watchdog timer supported
by Spreadtrum system.
# BLACKFIN Architecture
......@@ -1458,7 +1469,7 @@ config RC32434_WDT
config INDYDOG
tristate "Indy/I2 Hardware Watchdog"
depends on SGI_HAS_INDYDOG || (MIPS && COMPILE_TEST)
depends on SGI_HAS_INDYDOG
help
Hardware driver for the Indy's/I2's watchdog. This is a
watchdog timer that will reboot the machine after a 60 second
......
......@@ -46,7 +46,7 @@ obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_GEMINI_WATCHDOG) += gemini_wdt.o
obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o
obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
......@@ -88,9 +88,8 @@ obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o
obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o
obj-$(CONFIG_STM32_WATCHDOG) += stm32_iwdg.o
obj-$(CONFIG_UNIPHIER_WATCHDOG) += uniphier_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
obj-$(CONFIG_RTD119X_WATCHDOG) += rtd119x_wdt.o
obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o
# BLACKFIN Architecture
obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o
......
......@@ -181,7 +181,7 @@ static long advwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (advwdt_set_heartbeat(new_timeout))
return -EINVAL;
advwdt_ping();
/* Fall */
/* fall through */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
......
......@@ -223,8 +223,8 @@ static long ali_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (ali_settimer(new_timeout))
return -EINVAL;
ali_keepalive();
/* Fall */
}
/* fall through */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
......
......@@ -243,9 +243,13 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
if (of_property_read_bool(np, "aspeed,external-signal"))
wdt->ctrl |= WDT_CTRL_WDT_EXT;
writel(wdt->ctrl, wdt->base + WDT_CTRL);
if (readl(wdt->base + WDT_CTRL) & WDT_CTRL_ENABLE) {
/*
* The watchdog is running, but invoke aspeed_wdt_start() to
* write wdt->ctrl to WDT_CTRL to ensure the watchdog's
* configuration conforms to the driver's expectations.
* Primarily, ensure we're using the 1MHz clock source.
*/
aspeed_wdt_start(&wdt->wdd);
set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
}
......@@ -312,7 +316,18 @@ static struct platform_driver aspeed_watchdog_driver = {
.of_match_table = of_match_ptr(aspeed_wdt_of_table),
},
};
module_platform_driver(aspeed_watchdog_driver);
static int __init aspeed_wdt_init(void)
{
return platform_driver_register(&aspeed_watchdog_driver);
}
arch_initcall(aspeed_wdt_init);
static void __exit aspeed_wdt_exit(void)
{
platform_driver_unregister(&aspeed_watchdog_driver);
}
module_exit(aspeed_wdt_exit);
MODULE_DESCRIPTION("Aspeed Watchdog Driver");
MODULE_LICENSE("GPL");
This diff is collapsed.
......@@ -46,22 +46,6 @@ static void da9062_set_window_start(struct da9062_watchdog *wdt)
wdt->j_time_stamp = jiffies;
}
static void da9062_apply_window_protection(struct da9062_watchdog *wdt)
{
unsigned long delay = msecs_to_jiffies(DA9062_RESET_PROTECTION_MS);
unsigned long timeout = wdt->j_time_stamp + delay;
unsigned long now = jiffies;
unsigned int diff_ms;
/* if time-limit has not elapsed then wait for remainder */
if (time_before(now, timeout)) {
diff_ms = jiffies_to_msecs(timeout-now);
dev_dbg(wdt->hw->dev,
"Kicked too quickly. Delaying %u msecs\n", diff_ms);
msleep(diff_ms);
}
}
static unsigned int da9062_wdt_timeout_to_sel(unsigned int secs)
{
unsigned int i;
......@@ -78,8 +62,6 @@ static int da9062_reset_watchdog_timer(struct da9062_watchdog *wdt)
{
int ret;
da9062_apply_window_protection(wdt);
ret = regmap_update_bits(wdt->hw->regmap,
DA9062AA_CONTROL_F,
DA9062AA_WATCHDOG_MASK,
......@@ -100,6 +82,13 @@ static int da9062_wdt_update_timeout_register(struct da9062_watchdog *wdt,
if (ret)
return ret;
regmap_update_bits(chip->regmap,
DA9062AA_CONTROL_D,
DA9062AA_TWDSCALE_MASK,
DA9062_TWDSCALE_DISABLE);
usleep_range(150, 300);
return regmap_update_bits(chip->regmap,
DA9062AA_CONTROL_D,
DA9062AA_TWDSCALE_MASK,
......@@ -175,6 +164,25 @@ static int da9062_wdt_set_timeout(struct watchdog_device *wdd,
return ret;
}
static int da9062_wdt_restart(struct watchdog_device *wdd, unsigned long action,
void *data)
{
struct da9062_watchdog *wdt = watchdog_get_drvdata(wdd);
int ret;
ret = regmap_write(wdt->hw->regmap,
DA9062AA_CONTROL_F,
DA9062AA_SHUTDOWN_MASK);
if (ret)
dev_alert(wdt->hw->dev, "Failed to shutdown (err = %d)\n",
ret);
/* wait for reset to assert... */
mdelay(500);
return ret;
}
static const struct watchdog_info da9062_watchdog_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "DA9062 WDT",
......@@ -186,6 +194,7 @@ static const struct watchdog_ops da9062_watchdog_ops = {
.stop = da9062_wdt_stop,
.ping = da9062_wdt_ping,
.set_timeout = da9062_wdt_set_timeout,
.restart = da9062_wdt_restart,
};
static const struct of_device_id da9062_compatible_id_table[] = {
......@@ -215,10 +224,13 @@ static int da9062_wdt_probe(struct platform_device *pdev)
wdt->wdtdev.ops = &da9062_watchdog_ops;
wdt->wdtdev.min_timeout = DA9062_WDT_MIN_TIMEOUT;
wdt->wdtdev.max_timeout = DA9062_WDT_MAX_TIMEOUT;
wdt->wdtdev.min_hw_heartbeat_ms = DA9062_RESET_PROTECTION_MS;
wdt->wdtdev.timeout = DA9062_WDG_DEFAULT_TIMEOUT;
wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
wdt->wdtdev.parent = &pdev->dev;
watchdog_set_restart_priority(&wdt->wdtdev, 128);
watchdog_set_drvdata(&wdt->wdtdev, wdt);
ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev);
......
......@@ -140,6 +140,42 @@ static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd)
return wdd->timeout - timer_counter;
}
static int davinci_wdt_restart(struct watchdog_device *wdd,
unsigned long action, void *data)
{
struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
u32 tgcr, wdtcr;
/* disable, internal clock source */
iowrite32(0, davinci_wdt->base + TCR);
/* reset timer, set mode to 64-bit watchdog, and unreset */
tgcr = 0;
iowrite32(tgcr, davinci_wdt->base + TGCR);
tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
iowrite32(tgcr, davinci_wdt->base + TGCR);
/* clear counter and period regs */
iowrite32(0, davinci_wdt->base + TIM12);
iowrite32(0, davinci_wdt->base + TIM34);
iowrite32(0, davinci_wdt->base + PRD12);
iowrite32(0, davinci_wdt->base + PRD34);
/* put watchdog in pre-active state */
wdtcr = WDKEY_SEQ0 | WDEN;
iowrite32(wdtcr, davinci_wdt->base + WDTCR);
/* put watchdog in active state */
wdtcr = WDKEY_SEQ1 | WDEN;
iowrite32(wdtcr, davinci_wdt->base + WDTCR);
/* write an invalid value to the WDKEY field to trigger a restart */
wdtcr = 0x00004000;
iowrite32(wdtcr, davinci_wdt->base + WDTCR);
return 0;
}
static const struct watchdog_info davinci_wdt_info = {
.options = WDIOF_KEEPALIVEPING,
.identity = "DaVinci/Keystone Watchdog",
......@@ -151,6 +187,7 @@ static const struct watchdog_ops davinci_wdt_ops = {
.stop = davinci_wdt_ping,
.ping = davinci_wdt_ping,
.get_timeleft = davinci_wdt_get_timeleft,
.restart = davinci_wdt_restart,
};
static int davinci_wdt_probe(struct platform_device *pdev)
......@@ -195,6 +232,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(wdd, davinci_wdt);
watchdog_set_nowayout(wdd, 1);
watchdog_set_restart_priority(wdd, 128);
wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
davinci_wdt->base = devm_ioremap_resource(dev, wdt_mem);
......
......@@ -127,14 +127,27 @@ static int dw_wdt_start(struct watchdog_device *wdd)
dw_wdt_set_timeout(wdd, wdd->timeout);
set_bit(WDOG_HW_RUNNING, &wdd->status);
writel(WDOG_CONTROL_REG_WDT_EN_MASK,
dw_wdt->regs + WDOG_CONTROL_REG_OFFSET);
return 0;
}
static int dw_wdt_stop(struct watchdog_device *wdd)
{
struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
if (!dw_wdt->rst) {
set_bit(WDOG_HW_RUNNING, &wdd->status);
return 0;
}
reset_control_assert(dw_wdt->rst);
reset_control_deassert(dw_wdt->rst);
return 0;
}
static int dw_wdt_restart(struct watchdog_device *wdd,
unsigned long action, void *data)
{
......@@ -173,6 +186,7 @@ static const struct watchdog_info dw_wdt_ident = {
static const struct watchdog_ops dw_wdt_ops = {
.owner = THIS_MODULE,
.start = dw_wdt_start,
.stop = dw_wdt_stop,
.ping = dw_wdt_ping,
.set_timeout = dw_wdt_set_timeout,
.get_timeleft = dw_wdt_get_timeleft,
......
......@@ -290,7 +290,7 @@ static long eurwdt_ioctl(struct file *file,
eurwdt_timeout = time;
eurwdt_set_timeout(time);
spin_unlock(&eurwdt_lock);
/* Fall */
/* fall through */
case WDIOC_GETTIMEOUT:
return put_user(eurwdt_timeout, p);
......
......@@ -627,7 +627,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
if (new_options & WDIOS_ENABLECARD)
return watchdog_start();
/* fall through */
case WDIOC_KEEPALIVE:
watchdog_keepalive();
......@@ -641,7 +641,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
return -EINVAL;
watchdog_keepalive();
/* Fall */
/* fall through */
case WDIOC_GETTIMEOUT:
return put_user(watchdog.timeout, uarg.i);
......
/*
* Watchdog driver for Cortina Systems Gemini SoC
* Watchdog driver for Faraday Technology FTWDT010
*
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
*
......@@ -22,92 +22,98 @@
#include <linux/slab.h>
#include <linux/watchdog.h>
#define GEMINI_WDCOUNTER 0x0
#define GEMINI_WDLOAD 0x4
#define GEMINI_WDRESTART 0x8
#define GEMINI_WDCR 0xC
#define FTWDT010_WDCOUNTER 0x0
#define FTWDT010_WDLOAD 0x4
#define FTWDT010_WDRESTART 0x8
#define FTWDT010_WDCR 0xC
#define WDRESTART_MAGIC 0x5AB9
#define WDCR_CLOCK_5MHZ BIT(4)
#define WDCR_WDEXT BIT(3)
#define WDCR_WDINTR BIT(2)
#define WDCR_SYS_RST BIT(1)
#define WDCR_ENABLE BIT(0)
#define WDT_CLOCK 5000000 /* 5 MHz */
struct gemini_wdt {
struct ftwdt010_wdt {
struct watchdog_device wdd;
struct device *dev;
void __iomem *base;
bool has_irq;
};
static inline
struct gemini_wdt *to_gemini_wdt(struct watchdog_device *wdd)
struct ftwdt010_wdt *to_ftwdt010_wdt(struct watchdog_device *wdd)
{
return container_of(wdd, struct gemini_wdt, wdd);
return container_of(wdd, struct ftwdt010_wdt, wdd);
}
static int gemini_wdt_start(struct watchdog_device *wdd)
static int ftwdt010_wdt_start(struct watchdog_device *wdd)
{
struct gemini_wdt *gwdt = to_gemini_wdt(wdd);
struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
u32 enable;
writel(wdd->timeout * WDT_CLOCK, gwdt->base + GEMINI_WDLOAD);
writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART);
writel(wdd->timeout * WDT_CLOCK, gwdt->base + FTWDT010_WDLOAD);
writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
/* set clock before enabling */
writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST,
gwdt->base + GEMINI_WDCR);
writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE,
gwdt->base + GEMINI_WDCR);
enable = WDCR_CLOCK_5MHZ | WDCR_SYS_RST;
writel(enable, gwdt->base + FTWDT010_WDCR);
if (gwdt->has_irq)
enable |= WDCR_WDINTR;
enable |= WDCR_ENABLE;
writel(enable, gwdt->base + FTWDT010_WDCR);
return 0;
}
static int gemini_wdt_stop(struct watchdog_device *wdd)
static int ftwdt010_wdt_stop(struct watchdog_device *wdd)
{
struct gemini_wdt *gwdt = to_gemini_wdt(wdd);
struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
writel(0, gwdt->base + GEMINI_WDCR);
writel(0, gwdt->base + FTWDT010_WDCR);
return 0;
}
static int gemini_wdt_ping(struct watchdog_device *wdd)
static int ftwdt010_wdt_ping(struct watchdog_device *wdd)
{
struct gemini_wdt *gwdt = to_gemini_wdt(wdd);
struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART);
writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
return 0;
}
static int gemini_wdt_set_timeout(struct watchdog_device *wdd,
static int ftwdt010_wdt_set_timeout(struct watchdog_device *wdd,
unsigned int timeout)
{
wdd->timeout = timeout;
if (watchdog_active(wdd))
gemini_wdt_start(wdd);
ftwdt010_wdt_start(wdd);
return 0;
}
static irqreturn_t gemini_wdt_interrupt(int irq, void *data)
static irqreturn_t ftwdt010_wdt_interrupt(int irq, void *data)
{
struct gemini_wdt *gwdt = data;
struct ftwdt010_wdt *gwdt = data;
watchdog_notify_pretimeout(&gwdt->wdd);
return IRQ_HANDLED;
}
static const struct watchdog_ops gemini_wdt_ops = {
.start = gemini_wdt_start,
.stop = gemini_wdt_stop,
.ping = gemini_wdt_ping,
.set_timeout = gemini_wdt_set_timeout,
static const struct watchdog_ops ftwdt010_wdt_ops = {
.start = ftwdt010_wdt_start,
.stop = ftwdt010_wdt_stop,
.ping = ftwdt010_wdt_ping,
.set_timeout = ftwdt010_wdt_set_timeout,
.owner = THIS_MODULE,
};
static const struct watchdog_info gemini_wdt_info = {
static const struct watchdog_info ftwdt010_wdt_info = {
.options = WDIOF_KEEPALIVEPING
| WDIOF_MAGICCLOSE
| WDIOF_SETTIMEOUT,
......@@ -115,11 +121,11 @@ static const struct watchdog_info gemini_wdt_info = {
};
static int gemini_wdt_probe(struct platform_device *pdev)
static int ftwdt010_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct gemini_wdt *gwdt;
struct ftwdt010_wdt *gwdt;
unsigned int reg;
int irq;
int ret;
......@@ -133,13 +139,9 @@ static int gemini_wdt_probe(struct platform_device *pdev)
if (IS_ERR(gwdt->base))
return PTR_ERR(gwdt->base);
irq = platform_get_irq(pdev, 0);
if (!irq)
return -EINVAL;
gwdt->dev = dev;
gwdt->wdd.info = &gemini_wdt_info;
gwdt->wdd.ops = &gemini_wdt_ops;
gwdt->wdd.info = &ftwdt010_wdt_info;
gwdt->wdd.ops = &ftwdt010_wdt_ops;
gwdt->wdd.min_timeout = 1;
gwdt->wdd.max_timeout = 0xFFFFFFFF / WDT_CLOCK;
gwdt->wdd.parent = dev;
......@@ -151,17 +153,21 @@ static int gemini_wdt_probe(struct platform_device *pdev)
gwdt->wdd.timeout = 13U;
watchdog_init_timeout(&gwdt->wdd, 0, dev);
reg = readw(gwdt->base + GEMINI_WDCR);
reg = readw(gwdt->base + FTWDT010_WDCR);
if (reg & WDCR_ENABLE) {
/* Watchdog was enabled by the bootloader, disable it. */
reg &= ~WDCR_ENABLE;
writel(reg, gwdt->base + GEMINI_WDCR);
writel(reg, gwdt->base + FTWDT010_WDCR);
}
ret = devm_request_irq(dev, irq, gemini_wdt_interrupt, 0,
"watchdog bark", gwdt);
if (ret)
return ret;
irq = platform_get_irq(pdev, 0);
if (irq) {
ret = devm_request_irq(dev, irq, ftwdt010_wdt_interrupt, 0,
"watchdog bark", gwdt);
if (ret)
return ret;
gwdt->has_irq = true;
}
ret = devm_watchdog_register_device(dev, &gwdt->wdd);
if (ret) {
......@@ -171,59 +177,60 @@ static int gemini_wdt_probe(struct platform_device *pdev)
/* Set up platform driver data */
platform_set_drvdata(pdev, gwdt);
dev_info(dev, "Gemini watchdog driver enabled\n");
dev_info(dev, "FTWDT010 watchdog driver enabled\n");
return 0;
}
static int __maybe_unused gemini_wdt_suspend(struct device *dev)
static int __maybe_unused ftwdt010_wdt_suspend(struct device *dev)
{
struct gemini_wdt *gwdt = dev_get_drvdata(dev);
struct ftwdt010_wdt *gwdt = dev_get_drvdata(dev);
unsigned int reg;
reg = readw(gwdt->base + GEMINI_WDCR);
reg = readw(gwdt->base + FTWDT010_WDCR);
reg &= ~WDCR_ENABLE;
writel(reg, gwdt->base + GEMINI_WDCR);
writel(reg, gwdt->base + FTWDT010_WDCR);
return 0;
}
static int __maybe_unused gemini_wdt_resume(struct device *dev)
static int __maybe_unused ftwdt010_wdt_resume(struct device *dev)
{
struct gemini_wdt *gwdt = dev_get_drvdata(dev);
struct ftwdt010_wdt *gwdt = dev_get_drvdata(dev);
unsigned int reg;
if (watchdog_active(&gwdt->wdd)) {
reg = readw(gwdt->base + GEMINI_WDCR);
reg = readw(gwdt->base + FTWDT010_WDCR);
reg |= WDCR_ENABLE;
writel(reg, gwdt->base + GEMINI_WDCR);
writel(reg, gwdt->base + FTWDT010_WDCR);
}
return 0;
}
static const struct dev_pm_ops gemini_wdt_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(gemini_wdt_suspend,
gemini_wdt_resume)
static const struct dev_pm_ops ftwdt010_wdt_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ftwdt010_wdt_suspend,
ftwdt010_wdt_resume)
};
#ifdef CONFIG_OF
static const struct of_device_id gemini_wdt_match[] = {
static const struct of_device_id ftwdt010_wdt_match[] = {
{ .compatible = "faraday,ftwdt010" },
{ .compatible = "cortina,gemini-watchdog" },
{},
};
MODULE_DEVICE_TABLE(of, gemini_wdt_match);
MODULE_DEVICE_TABLE(of, ftwdt010_wdt_match);
#endif
static struct platform_driver gemini_wdt_driver = {
.probe = gemini_wdt_probe,
static struct platform_driver ftwdt010_wdt_driver = {
.probe = ftwdt010_wdt_probe,
.driver = {
.name = "gemini-wdt",
.of_match_table = of_match_ptr(gemini_wdt_match),
.pm = &gemini_wdt_dev_pm_ops,
.name = "ftwdt010-wdt",
.of_match_table = of_match_ptr(ftwdt010_wdt_match),
.pm = &ftwdt010_wdt_dev_pm_ops,
},
};
module_platform_driver(gemini_wdt_driver);
module_platform_driver(ftwdt010_wdt_driver);
MODULE_AUTHOR("Linus Walleij");
MODULE_DESCRIPTION("Watchdog driver for Gemini");
MODULE_DESCRIPTION("Watchdog driver for Faraday Technology FTWDT010");
MODULE_LICENSE("GPL");
......@@ -12,7 +12,8 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
......@@ -25,8 +26,7 @@ enum {
};
struct gpio_wdt_priv {
int gpio;
bool active_low;
struct gpio_desc *gpiod;
bool state;
bool always_running;
unsigned int hw_algo;
......@@ -35,11 +35,12 @@ struct gpio_wdt_priv {
static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
{
gpio_set_value_cansleep(priv->gpio, !priv->active_low);
/* Eternal ping */
gpiod_set_value_cansleep(priv->gpiod, 1);
/* Put GPIO back to tristate */
if (priv->hw_algo == HW_ALGO_TOGGLE)
gpio_direction_input(priv->gpio);
gpiod_direction_input(priv->gpiod);
}
static int gpio_wdt_ping(struct watchdog_device *wdd)
......@@ -50,13 +51,13 @@ static int gpio_wdt_ping(struct watchdog_device *wdd)
case HW_ALGO_TOGGLE:
/* Toggle output pin */
priv->state = !priv->state;
gpio_set_value_cansleep(priv->gpio, priv->state);
gpiod_set_value_cansleep(priv->gpiod, priv->state);
break;
case HW_ALGO_LEVEL:
/* Pulse */
gpio_set_value_cansleep(priv->gpio, !priv->active_low);
gpiod_set_value_cansleep(priv->gpiod, 1);
udelay(1);
gpio_set_value_cansleep(priv->gpio, priv->active_low);
gpiod_set_value_cansleep(priv->gpiod, 0);
break;
}
return 0;
......@@ -66,8 +67,8 @@ static int gpio_wdt_start(struct watchdog_device *wdd)
{
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
priv->state = priv->active_low;
gpio_direction_output(priv->gpio, priv->state);
priv->state = 0;
gpiod_direction_output(priv->gpiod, priv->state);
set_bit(WDOG_HW_RUNNING, &wdd->status);
......@@ -80,7 +81,8 @@ static int gpio_wdt_stop(struct watchdog_device *wdd)
if (!priv->always_running) {
gpio_wdt_disable(priv);
clear_bit(WDOG_HW_RUNNING, &wdd->status);
} else {
set_bit(WDOG_HW_RUNNING, &wdd->status);
}
return 0;
......@@ -101,44 +103,38 @@ static const struct watchdog_ops gpio_wdt_ops = {
static int gpio_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct gpio_wdt_priv *priv;
enum of_gpio_flags flags;
enum gpiod_flags gflags;
unsigned int hw_margin;
unsigned long f = 0;
const char *algo;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
priv->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags);
if (!gpio_is_valid(priv->gpio))
return priv->gpio;
priv->active_low = flags & OF_GPIO_ACTIVE_LOW;
ret = of_property_read_string(pdev->dev.of_node, "hw_algo", &algo);
ret = of_property_read_string(np, "hw_algo", &algo);
if (ret)
return ret;
if (!strcmp(algo, "toggle")) {
priv->hw_algo = HW_ALGO_TOGGLE;
f = GPIOF_IN;
gflags = GPIOD_IN;
} else if (!strcmp(algo, "level")) {
priv->hw_algo = HW_ALGO_LEVEL;
f = priv->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
gflags = GPIOD_OUT_LOW;
} else {
return -EINVAL;
}
ret = devm_gpio_request_one(&pdev->dev, priv->gpio, f,
dev_name(&pdev->dev));
if (ret)
return ret;
priv->gpiod = devm_gpiod_get(dev, NULL, gflags);
if (IS_ERR(priv->gpiod))
return PTR_ERR(priv->gpiod);
ret = of_property_read_u32(pdev->dev.of_node,
ret = of_property_read_u32(np,
"hw_margin_ms", &hw_margin);
if (ret)
return ret;
......@@ -146,7 +142,7 @@ static int gpio_wdt_probe(struct platform_device *pdev)
if (hw_margin < 2 || hw_margin > 65535)
return -EINVAL;
priv->always_running = of_property_read_bool(pdev->dev.of_node,
priv->always_running = of_property_read_bool(np,
"always-running");
watchdog_set_drvdata(&priv->wdd, priv);
......@@ -155,9 +151,9 @@ static int gpio_wdt_probe(struct platform_device *pdev)
priv->wdd.ops = &gpio_wdt_ops;
priv->wdd.min_timeout = SOFT_TIMEOUT_MIN;
priv->wdd.max_hw_heartbeat_ms = hw_margin;
priv->wdd.parent = &pdev->dev;
priv->wdd.parent = dev;
if (watchdog_init_timeout(&priv->wdd, 0, &pdev->dev) < 0)
if (watchdog_init_timeout(&priv->wdd, 0, dev) < 0)
priv->wdd.timeout = SOFT_TIMEOUT_DEF;
watchdog_stop_on_reboot(&priv->wdd);
......
......@@ -52,6 +52,7 @@ static char expect_release;
static unsigned long hpwdt_is_open;
static void __iomem *pci_mem_addr; /* the PCI-memory address */
static unsigned long __iomem *hpwdt_nmistat;
static unsigned long __iomem *hpwdt_timer_reg;
static unsigned long __iomem *hpwdt_timer_con;
......@@ -475,6 +476,11 @@ static int hpwdt_time_left(void)
}
#ifdef CONFIG_HPWDT_NMI_DECODING
static int hpwdt_my_nmi(void)
{
return ioread8(hpwdt_nmistat) & 0x6;
}
/*
* NMI Handler
*/
......@@ -486,6 +492,9 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
if (!hpwdt_nmi_decoding)
return NMI_DONE;
if ((ulReason == NMI_UNKNOWN) && !hpwdt_my_nmi())
return NMI_DONE;
spin_lock_irqsave(&rom_lock, rom_pl);
if (!die_nmi_called && !is_icru && !is_uefi)
asminline_call(&cmn_regs, cru_rom_addr);
......@@ -700,7 +709,7 @@ static void dmi_find_icru(const struct dmi_header *dm, void *dummy)
smbios_proliant_ptr = (struct smbios_proliant_info *) dm;
if (smbios_proliant_ptr->misc_features & 0x01)
is_icru = 1;
if (smbios_proliant_ptr->misc_features & 0x408)
if (smbios_proliant_ptr->misc_features & 0x1400)
is_uefi = 1;
}
}
......@@ -842,6 +851,7 @@ static int hpwdt_init_one(struct pci_dev *dev,
retval = -ENOMEM;
goto error_pci_iomap;
}
hpwdt_nmistat = pci_mem_addr + 0x6e;
hpwdt_timer_reg = pci_mem_addr + 0x70;
hpwdt_timer_con = pci_mem_addr + 0x72;
......
This diff is collapsed.
......@@ -218,7 +218,7 @@ static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (ibwdt_set_heartbeat(new_margin))
return -EINVAL;
ibwdt_ping();
/* Fall */
/* fall through */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
......
......@@ -169,15 +169,21 @@ static int imx2_wdt_ping(struct watchdog_device *wdog)
return 0;
}
static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
unsigned int new_timeout)
static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
unsigned int new_timeout)
{
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
wdog->timeout = new_timeout;
regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
WDOG_SEC_TO_COUNT(new_timeout));
}
static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
unsigned int new_timeout)
{
__imx2_wdt_set_timeout(wdog, new_timeout);
wdog->timeout = new_timeout;
return 0;
}
......@@ -371,7 +377,11 @@ static int imx2_wdt_suspend(struct device *dev)
/* The watchdog IP block is running */
if (imx2_wdt_is_running(wdev)) {
imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
/*
* Don't update wdog->timeout, we'll restore the current value
* during resume.
*/
__imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
imx2_wdt_ping(wdog);
}
......
......@@ -146,6 +146,7 @@ static const struct watchdog_ops jz4740_wdt_ops = {
#ifdef CONFIG_OF
static const struct of_device_id jz4740_wdt_of_matches[] = {
{ .compatible = "ingenic,jz4740-watchdog", },
{ .compatible = "ingenic,jz4780-watchdog", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, jz4740_wdt_of_matches);
......
......@@ -526,12 +526,11 @@ static ssize_t mei_dbgfs_read_state(struct file *file, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct mei_wdt *wdt = file->private_data;
const size_t bufsz = 32;
char buf[bufsz];
char buf[32];
ssize_t pos;
pos = scnprintf(buf, bufsz, "state: %s\n",
mei_wdt_state_str(wdt->state));
pos = scnprintf(buf, sizeof(buf), "state: %s\n",
mei_wdt_state_str(wdt->state));
return simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
}
......
......@@ -22,7 +22,6 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/module.h>
......@@ -31,10 +30,13 @@
#include <linux/uaccess.h>
#include <sysdev/fsl_soc.h>
#define WATCHDOG_TIMEOUT 10
struct mpc8xxx_wdt {
__be32 res0;
__be32 swcrr; /* System watchdog control register */
#define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
#define SWCRR_SWF 0x00000008 /* Software Watchdog Freeze (mpc8xx). */
#define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */
#define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/
#define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */
......@@ -52,14 +54,15 @@ struct mpc8xxx_wdt_type {
struct mpc8xxx_wdt_ddata {
struct mpc8xxx_wdt __iomem *base;
struct watchdog_device wdd;
struct timer_list timer;
spinlock_t lock;
u16 swtc;
};
static u16 timeout = 0xffff;
static u16 timeout;
module_param(timeout, ushort, 0);
MODULE_PARM_DESC(timeout,
"Watchdog timeout in ticks. (0<timeout<65536, default=65535)");
"Watchdog timeout in seconds. (1<timeout<65535, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static bool reset = 1;
module_param(reset, bool, 0);
......@@ -80,31 +83,27 @@ static void mpc8xxx_wdt_keepalive(struct mpc8xxx_wdt_ddata *ddata)
spin_unlock(&ddata->lock);
}
static void mpc8xxx_wdt_timer_ping(struct timer_list *t)
{
struct mpc8xxx_wdt_ddata *ddata = from_timer(ddata, t, timer);
mpc8xxx_wdt_keepalive(ddata);
/* We're pinging it twice faster than needed, just to be sure. */
mod_timer(&ddata->timer, jiffies + HZ * ddata->wdd.timeout / 2);
}
static int mpc8xxx_wdt_start(struct watchdog_device *w)
{
struct mpc8xxx_wdt_ddata *ddata =
container_of(w, struct mpc8xxx_wdt_ddata, wdd);
u32 tmp = SWCRR_SWEN | SWCRR_SWPR;
u32 tmp = in_be32(&ddata->base->swcrr);
/* Good, fire up the show */
tmp &= ~(SWCRR_SWTC | SWCRR_SWF | SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR);
tmp |= SWCRR_SWEN | SWCRR_SWPR | (ddata->swtc << 16);
if (reset)
tmp |= SWCRR_SWRI;
tmp |= timeout << 16;
out_be32(&ddata->base->swcrr, tmp);
del_timer_sync(&ddata->timer);
tmp = in_be32(&ddata->base->swcrr);
if (!(tmp & SWCRR_SWEN))
return -EOPNOTSUPP;
ddata->swtc = tmp >> 16;
set_bit(WDOG_HW_RUNNING, &ddata->wdd.status);
return 0;
}
......@@ -118,17 +117,8 @@ static int mpc8xxx_wdt_ping(struct watchdog_device *w)
return 0;
}
static int mpc8xxx_wdt_stop(struct watchdog_device *w)
{
struct mpc8xxx_wdt_ddata *ddata =
container_of(w, struct mpc8xxx_wdt_ddata, wdd);
mod_timer(&ddata->timer, jiffies);
return 0;
}
static struct watchdog_info mpc8xxx_wdt_info = {
.options = WDIOF_KEEPALIVEPING,
.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT,
.firmware_version = 1,
.identity = "MPC8xxx",
};
......@@ -137,7 +127,6 @@ static struct watchdog_ops mpc8xxx_wdt_ops = {
.owner = THIS_MODULE,
.start = mpc8xxx_wdt_start,
.ping = mpc8xxx_wdt_ping,
.stop = mpc8xxx_wdt_stop,
};
static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
......@@ -148,7 +137,6 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
struct mpc8xxx_wdt_ddata *ddata;
u32 freq = fsl_get_sys_freq();
bool enabled;
unsigned int timeout_sec;
wdt_type = of_device_get_match_data(&ofdev->dev);
if (!wdt_type)
......@@ -173,26 +161,17 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
}
spin_lock_init(&ddata->lock);
timer_setup(&ddata->timer, mpc8xxx_wdt_timer_ping, 0);
ddata->wdd.info = &mpc8xxx_wdt_info,
ddata->wdd.ops = &mpc8xxx_wdt_ops,
/* Calculate the timeout in seconds */
timeout_sec = (timeout * wdt_type->prescaler) / freq;
ddata->wdd.timeout = timeout_sec;
ddata->wdd.timeout = WATCHDOG_TIMEOUT;
watchdog_init_timeout(&ddata->wdd, timeout, &ofdev->dev);
watchdog_set_nowayout(&ddata->wdd, nowayout);
ret = watchdog_register_device(&ddata->wdd);
if (ret) {
pr_err("cannot register watchdog device (err=%d)\n", ret);
return ret;
}
pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n",
reset ? "reset" : "interrupt", timeout, timeout_sec);
ddata->swtc = min(ddata->wdd.timeout * freq / wdt_type->prescaler,
0xffffU);
/*
* If the watchdog was previously enabled or we're running on
......@@ -200,7 +179,22 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
* userspace handles it.
*/
if (enabled)
mod_timer(&ddata->timer, jiffies);
mpc8xxx_wdt_start(&ddata->wdd);
ddata->wdd.max_hw_heartbeat_ms = (ddata->swtc * wdt_type->prescaler) /
(freq / 1000);
ddata->wdd.min_timeout = ddata->wdd.max_hw_heartbeat_ms / 1000;
if (ddata->wdd.timeout < ddata->wdd.min_timeout)
ddata->wdd.timeout = ddata->wdd.min_timeout;
ret = watchdog_register_device(&ddata->wdd);
if (ret) {
pr_err("cannot register watchdog device (err=%d)\n", ret);
return ret;
}
pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n",
reset ? "reset" : "interrupt", ddata->wdd.timeout);
platform_set_drvdata(ofdev, ddata);
return 0;
......@@ -212,7 +206,6 @@ static int mpc8xxx_wdt_remove(struct platform_device *ofdev)
pr_crit("Watchdog removed, expect the %s soon!\n",
reset ? "reset" : "machine check exception");
del_timer_sync(&ddata->timer);
watchdog_unregister_device(&ddata->wdd);
return 0;
......
......@@ -105,6 +105,11 @@ static int mt7621_wdt_bootcause(void)
return 0;
}
static int mt7621_wdt_is_running(struct watchdog_device *w)
{
return !!(rt_wdt_r32(TIMER_REG_TMR1CTL) & TMR1CTL_ENABLE);
}
static const struct watchdog_info mt7621_wdt_info = {
.identity = "Mediatek Watchdog",
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
......@@ -128,7 +133,6 @@ static struct watchdog_device mt7621_wdt_dev = {
static int mt7621_wdt_probe(struct platform_device *pdev)
{
struct resource *res;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mt7621_wdt_base = devm_ioremap_resource(&pdev->dev, res);
......@@ -144,17 +148,22 @@ static int mt7621_wdt_probe(struct platform_device *pdev)
watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout,
&pdev->dev);
watchdog_set_nowayout(&mt7621_wdt_dev, nowayout);
ret = watchdog_register_device(&mt7621_wdt_dev);
return 0;
}
static int mt7621_wdt_remove(struct platform_device *pdev)
{
watchdog_unregister_device(&mt7621_wdt_dev);
return 0;
if (mt7621_wdt_is_running(&mt7621_wdt_dev)) {
/*
* Make sure to apply timeout from watchdog core, taking
* the prescaler of this driver here into account (the
* boot loader might be using a different prescaler).
*
* To avoid spurious resets because of different scaling,
* we first disable the watchdog, set the new prescaler
* and timeout, and then re-enable the watchdog.
*/
mt7621_wdt_stop(&mt7621_wdt_dev);
mt7621_wdt_start(&mt7621_wdt_dev);
set_bit(WDOG_HW_RUNNING, &mt7621_wdt_dev.status);
}
return devm_watchdog_register_device(&pdev->dev, &mt7621_wdt_dev);
}
static void mt7621_wdt_shutdown(struct platform_device *pdev)
......@@ -170,7 +179,6 @@ MODULE_DEVICE_TABLE(of, mt7621_wdt_match);
static struct platform_driver mt7621_wdt_driver = {
.probe = mt7621_wdt_probe,
.remove = mt7621_wdt_remove,
.shutdown = mt7621_wdt_shutdown,
.driver = {
.name = KBUILD_MODNAME,
......
......@@ -576,7 +576,7 @@ static int orion_wdt_probe(struct platform_device *pdev)
/*
* Let's make sure the watchdog is fully stopped, unless it's
* explicitly enabled. This may be the case if the module was
* removed and re-insterted, or if the bootloader explicitly
* removed and re-inserted, or if the bootloader explicitly
* set a running watchdog before booting the kernel.
*/
if (!orion_wdt_enabled(&dev->wdt))
......
......@@ -545,8 +545,8 @@ static long pcipcwd_ioctl(struct file *file, unsigned int cmd,
return -EINVAL;
pcipcwd_keepalive();
/* Fall */
}
/* fall through */
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
......
......@@ -49,12 +49,11 @@
#define DRIVER_VERSION "1.02"
#define DRIVER_AUTHOR "Wim Van Sebroeck <wim@iguana.be>"
#define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
#define DRIVER_LICENSE "GPL"
#define DRIVER_NAME "pcwd_usb"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
MODULE_LICENSE("GPL");
#define WATCHDOG_HEARTBEAT 0 /* default heartbeat =
delay-time from dip-switches */
......@@ -456,8 +455,8 @@ static long usb_pcwd_ioctl(struct file *file, unsigned int cmd,
return -EINVAL;
usb_pcwd_keepalive(usb_pcwd_device);
/* Fall */
}
/* fall through */
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
......
/*
* Realtek RTD129x watchdog
*
* Copyright (c) 2017 Andreas Färber
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#define RTD119X_TCWCR 0x0
#define RTD119X_TCWTR 0x4
#define RTD119X_TCWOV 0xc
#define RTD119X_TCWCR_WDEN_DISABLED 0xa5
#define RTD119X_TCWCR_WDEN_ENABLED 0xff
#define RTD119X_TCWCR_WDEN_MASK 0xff
#define RTD119X_TCWTR_WDCLR BIT(0)
struct rtd119x_watchdog_device {
struct watchdog_device wdt_dev;
void __iomem *base;
struct clk *clk;
};
static int rtd119x_wdt_start(struct watchdog_device *wdev)
{
struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
u32 val;
val = readl_relaxed(data->base + RTD119X_TCWCR);
val &= ~RTD119X_TCWCR_WDEN_MASK;
val |= RTD119X_TCWCR_WDEN_ENABLED;
writel(val, data->base + RTD119X_TCWCR);
return 0;
}
static int rtd119x_wdt_stop(struct watchdog_device *wdev)
{
struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
u32 val;
val = readl_relaxed(data->base + RTD119X_TCWCR);
val &= ~RTD119X_TCWCR_WDEN_MASK;
val |= RTD119X_TCWCR_WDEN_DISABLED;
writel(val, data->base + RTD119X_TCWCR);
return 0;
}
static int rtd119x_wdt_ping(struct watchdog_device *wdev)
{
struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
writel_relaxed(RTD119X_TCWTR_WDCLR, data->base + RTD119X_TCWTR);
return rtd119x_wdt_start(wdev);
}
static int rtd119x_wdt_set_timeout(struct watchdog_device *wdev, unsigned int val)
{
struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
writel(val * clk_get_rate(data->clk), data->base + RTD119X_TCWOV);
data->wdt_dev.timeout = val;
return 0;
}
static const struct watchdog_ops rtd119x_wdt_ops = {
.owner = THIS_MODULE,
.start = rtd119x_wdt_start,
.stop = rtd119x_wdt_stop,
.ping = rtd119x_wdt_ping,
.set_timeout = rtd119x_wdt_set_timeout,
};
static const struct watchdog_info rtd119x_wdt_info = {
.identity = "rtd119x-wdt",
.options = 0,
};
static const struct of_device_id rtd119x_wdt_dt_ids[] = {
{ .compatible = "realtek,rtd1295-watchdog" },
{ }
};
static int rtd119x_wdt_probe(struct platform_device *pdev)
{
struct rtd119x_watchdog_device *data;
struct resource *res;
int ret;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
data->clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(data->clk))
return PTR_ERR(data->clk);
ret = clk_prepare_enable(data->clk);
if (ret) {
clk_put(data->clk);
return ret;
}
data->wdt_dev.info = &rtd119x_wdt_info;
data->wdt_dev.ops = &rtd119x_wdt_ops;
data->wdt_dev.timeout = 120;
data->wdt_dev.max_timeout = 0xffffffff / clk_get_rate(data->clk);
data->wdt_dev.min_timeout = 1;
data->wdt_dev.parent = &pdev->dev;
watchdog_stop_on_reboot(&data->wdt_dev);
watchdog_set_drvdata(&data->wdt_dev, data);
platform_set_drvdata(pdev, data);
writel_relaxed(RTD119X_TCWTR_WDCLR, data->base + RTD119X_TCWTR);
rtd119x_wdt_set_timeout(&data->wdt_dev, data->wdt_dev.timeout);
rtd119x_wdt_stop(&data->wdt_dev);
ret = devm_watchdog_register_device(&pdev->dev, &data->wdt_dev);
if (ret) {
clk_disable_unprepare(data->clk);
clk_put(data->clk);
return ret;
}
return 0;
}
static int rtd119x_wdt_remove(struct platform_device *pdev)
{
struct rtd119x_watchdog_device *data = platform_get_drvdata(pdev);
watchdog_unregister_device(&data->wdt_dev);
clk_disable_unprepare(data->clk);
clk_put(data->clk);
return 0;
}
static struct platform_driver rtd119x_wdt_driver = {
.probe = rtd119x_wdt_probe,
.remove = rtd119x_wdt_remove,
.driver = {
.name = "rtd1295-watchdog",
.of_match_table = rtd119x_wdt_dt_ids,
},
};
builtin_platform_driver(rtd119x_wdt_driver);
This diff is collapsed.
......@@ -7,6 +7,8 @@
* TCO timer driver for sp5100 chipsets
*/
#include <linux/bitops.h>
/*
* Some address definitions for the Watchdog
*/
......@@ -14,8 +16,11 @@
#define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */
#define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */
#define SP5100_WDT_START_STOP_BIT (1 << 0)
#define SP5100_WDT_TRIGGER_BIT (1 << 7)
#define SP5100_WDT_START_STOP_BIT BIT(0)
#define SP5100_WDT_FIRED BIT(1)
#define SP5100_WDT_ACTION_RESET BIT(2)
#define SP5100_WDT_DISABLED BIT(3)
#define SP5100_WDT_TRIGGER_BIT BIT(7)
#define SP5100_PM_IOPORTS_SIZE 0x02
......@@ -24,43 +29,57 @@
* read them from a register.
*/
/* For SP5100/SB7x0 chipset */
/* For SP5100/SB7x0/SB8x0 chipset */
#define SP5100_IO_PM_INDEX_REG 0xCD6
#define SP5100_IO_PM_DATA_REG 0xCD7
/* For SP5100/SB7x0 chipset */
#define SP5100_SB_RESOURCE_MMIO_BASE 0x9C
#define SP5100_PM_WATCHDOG_CONTROL 0x69
#define SP5100_PM_WATCHDOG_BASE 0x6C
#define SP5100_PM_WATCHDOG_FIRED (1 << 1)
#define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2)
#define SP5100_PCI_WATCHDOG_MISC_REG 0x41
#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3)
#define SP5100_PCI_WATCHDOG_DECODE_EN BIT(3)
#define SP5100_PM_WATCHDOG_DISABLE (1 << 0)
#define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1)
#define SP5100_PM_WATCHDOG_DISABLE ((u8)BIT(0))
#define SP5100_PM_WATCHDOG_SECOND_RES GENMASK(2, 1)
#define SP5100_DEVNAME "SP5100 TCO"
/* For SB8x0(or later) chipset */
#define SB800_IO_PM_INDEX_REG 0xCD6
#define SB800_IO_PM_DATA_REG 0xCD7
#define SB800_PM_ACPI_MMIO_EN 0x24
#define SB800_PM_WATCHDOG_CONTROL 0x48
#define SB800_PM_WATCHDOG_BASE 0x48
#define SB800_PM_WATCHDOG_CONFIG 0x4C
#define SB800_PCI_WATCHDOG_DECODE_EN (1 << 0)
#define SB800_PM_WATCHDOG_DISABLE (1 << 2)
#define SB800_PM_WATCHDOG_SECOND_RES (3 << 0)
#define SB800_ACPI_MMIO_DECODE_EN (1 << 0)
#define SB800_ACPI_MMIO_SEL (1 << 1)
#define SB800_PCI_WATCHDOG_DECODE_EN BIT(0)
#define SB800_PM_WATCHDOG_DISABLE ((u8)BIT(1))
#define SB800_PM_WATCHDOG_SECOND_RES GENMASK(1, 0)
#define SB800_ACPI_MMIO_DECODE_EN BIT(0)
#define SB800_ACPI_MMIO_SEL BIT(1)
#define SB800_PM_WDT_MMIO_OFFSET 0xB00
#define SB800_DEVNAME "SB800 TCO"
/* For recent chips with embedded FCH (rev 40+) */
#define EFCH_PM_DECODEEN 0x00
#define EFCH_PM_DECODEEN_WDT_TMREN BIT(7)
#define EFCH_PM_DECODEEN3 0x00
#define EFCH_PM_DECODEEN_SECOND_RES GENMASK(1, 0)
#define EFCH_PM_WATCHDOG_DISABLE ((u8)GENMASK(3, 2))
/* WDT MMIO if enabled with PM00_DECODEEN_WDT_TMREN */
#define EFCH_PM_WDT_ADDR 0xfeb00000
#define EFCH_PM_ISACONTROL 0x04
#define EFCH_PM_ISACONTROL_MMIOEN BIT(1)
#define EFCH_PM_ACPI_MMIO_ADDR 0xfed80000
#define EFCH_PM_ACPI_MMIO_WDT_OFFSET 0x00000b00
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for STM32 Independent Watchdog
*
* Copyright (C) Yannick Fertre 2017
* Author: Yannick Fertre <yannick.fertre@st.com>
* Copyright (C) STMicroelectronics 2017
* Author: Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics.
*
* This driver is based on tegra_wdt.c
*
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/clk.h>
......
......@@ -234,7 +234,6 @@ MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids);
static int sunxi_wdt_probe(struct platform_device *pdev)
{
struct sunxi_wdt_dev *sunxi_wdt;
const struct of_device_id *device;
struct resource *res;
int err;
......@@ -242,12 +241,10 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
if (!sunxi_wdt)
return -EINVAL;
device = of_match_device(sunxi_wdt_dt_ids, &pdev->dev);
if (!device)
sunxi_wdt->wdt_regs = of_device_get_match_data(&pdev->dev);
if (!sunxi_wdt->wdt_regs)
return -ENODEV;
sunxi_wdt->wdt_regs = device->data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sunxi_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(sunxi_wdt->wdt_base))
......
......@@ -97,6 +97,7 @@ static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
/**
* watchdog_init_timeout() - initialize the timeout field
* @wdd: watchdog device
* @timeout_parm: timeout module parameter
* @dev: Device that stores the timeout-sec property
*
......
This diff is collapsed.
......@@ -430,7 +430,7 @@ static long wdtpci_ioctl(struct file *file, unsigned int cmd,
if (wdtpci_set_heartbeat(new_heartbeat))
return -EINVAL;
wdtpci_ping();
/* Fall */
/* fall through */
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
default:
......
......@@ -9,10 +9,7 @@
* 2 of the License, or (at your option) any later version.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define DRV_NAME "wdt"
#define DRV_VERSION "0.01"
#define DRV_NAME "xen_wdt"
#include <linux/bug.h>
#include <linux/errno.h>
......@@ -21,25 +18,20 @@
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
#include <xen/xen.h>
#include <asm/xen/hypercall.h>
#include <xen/interface/sched.h>
static struct platform_device *platform_device;
static DEFINE_SPINLOCK(wdt_lock);
static struct sched_watchdog wdt;
static __kernel_time_t wdt_expires;
static bool is_active, expect_release;
static time64_t wdt_expires;
#define WATCHDOG_TIMEOUT 60 /* in seconds */
static unsigned int timeout = WATCHDOG_TIMEOUT;
static unsigned int timeout;
module_param(timeout, uint, S_IRUGO);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds "
"(default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
......@@ -49,20 +41,18 @@ module_param(nowayout, bool, S_IRUGO);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static inline __kernel_time_t set_timeout(void)
static inline time64_t set_timeout(struct watchdog_device *wdd)
{
wdt.timeout = timeout;
return ktime_to_timespec(ktime_get()).tv_sec + timeout;
wdt.timeout = wdd->timeout;
return ktime_get_seconds() + wdd->timeout;
}
static int xen_wdt_start(void)
static int xen_wdt_start(struct watchdog_device *wdd)
{
__kernel_time_t expires;
time64_t expires;
int err;
spin_lock(&wdt_lock);
expires = set_timeout();
expires = set_timeout(wdd);
if (!wdt.id)
err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
else
......@@ -74,36 +64,28 @@ static int xen_wdt_start(void)
} else
BUG_ON(!err);
spin_unlock(&wdt_lock);
return err;
}
static int xen_wdt_stop(void)
static int xen_wdt_stop(struct watchdog_device *wdd)
{
int err = 0;
spin_lock(&wdt_lock);
wdt.timeout = 0;
if (wdt.id)
err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
if (!err)
wdt.id = 0;
spin_unlock(&wdt_lock);
return err;
}
static int xen_wdt_kick(void)
static int xen_wdt_kick(struct watchdog_device *wdd)
{
__kernel_time_t expires;
time64_t expires;
int err;
spin_lock(&wdt_lock);
expires = set_timeout();
expires = set_timeout(wdd);
if (wdt.id)
err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
else
......@@ -111,195 +93,72 @@ static int xen_wdt_kick(void)
if (!err)
wdt_expires = expires;
spin_unlock(&wdt_lock);
return err;
}
static int xen_wdt_open(struct inode *inode, struct file *file)
{
int err;
/* /dev/watchdog can only be opened once */
if (xchg(&is_active, true))
return -EBUSY;
err = xen_wdt_start();
if (err == -EBUSY)
err = xen_wdt_kick();
return err ?: nonseekable_open(inode, file);
}
static int xen_wdt_release(struct inode *inode, struct file *file)
{
int err = 0;
if (expect_release)
err = xen_wdt_stop();
else {
pr_crit("unexpected close, not stopping watchdog!\n");
xen_wdt_kick();
}
is_active = err;
expect_release = false;
return err;
}
static ssize_t xen_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
static unsigned int xen_wdt_get_timeleft(struct watchdog_device *wdd)
{
/* See if we got the magic character 'V' and reload the timer */
if (len) {
if (!nowayout) {
size_t i;
/* in case it was set long ago */
expect_release = false;
/* scan to see whether or not we got the magic
character */
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_release = true;
}
}
/* someone wrote to us, we should reload the timer */
xen_wdt_kick();
}
return len;
return wdt_expires - ktime_get_seconds();
}
static long xen_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int new_options, retval = -EINVAL;
int new_timeout;
int __user *argp = (void __user *)arg;
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = DRV_NAME,
};
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, argp);
case WDIOC_SETOPTIONS:
if (get_user(new_options, argp))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD)
retval = xen_wdt_stop();
if (new_options & WDIOS_ENABLECARD) {
retval = xen_wdt_start();
if (retval == -EBUSY)
retval = xen_wdt_kick();
}
return retval;
case WDIOC_KEEPALIVE:
xen_wdt_kick();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, argp))
return -EFAULT;
if (!new_timeout)
return -EINVAL;
timeout = new_timeout;
xen_wdt_kick();
/* fall through */
case WDIOC_GETTIMEOUT:
return put_user(timeout, argp);
case WDIOC_GETTIMELEFT:
retval = wdt_expires - ktime_to_timespec(ktime_get()).tv_sec;
return put_user(retval, argp);
}
return -ENOTTY;
}
static struct watchdog_info xen_wdt_info = {
.identity = DRV_NAME,
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
};
static const struct file_operations xen_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = xen_wdt_write,
.unlocked_ioctl = xen_wdt_ioctl,
.open = xen_wdt_open,
.release = xen_wdt_release,
static const struct watchdog_ops xen_wdt_ops = {
.owner = THIS_MODULE,
.start = xen_wdt_start,
.stop = xen_wdt_stop,
.ping = xen_wdt_kick,
.get_timeleft = xen_wdt_get_timeleft,
};
static struct miscdevice xen_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &xen_wdt_fops,
static struct watchdog_device xen_wdt_dev = {
.info = &xen_wdt_info,
.ops = &xen_wdt_ops,
.timeout = WATCHDOG_TIMEOUT,
};
static int xen_wdt_probe(struct platform_device *dev)
static int xen_wdt_probe(struct platform_device *pdev)
{
struct sched_watchdog wd = { .id = ~0 };
int ret = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wd);
switch (ret) {
case -EINVAL:
if (!timeout) {
timeout = WATCHDOG_TIMEOUT;
pr_info("timeout value invalid, using %d\n", timeout);
}
ret = misc_register(&xen_wdt_miscdev);
if (ret) {
pr_err("cannot register miscdev on minor=%d (%d)\n",
WATCHDOG_MINOR, ret);
break;
}
pr_info("initialized (timeout=%ds, nowayout=%d)\n",
timeout, nowayout);
break;
case -ENOSYS:
pr_info("not supported\n");
ret = -ENODEV;
break;
default:
pr_info("bogus return value %d\n", ret);
break;
if (ret == -ENOSYS) {
dev_err(&pdev->dev, "watchdog not supported by hypervisor\n");
return -ENODEV;
}
return ret;
}
if (ret != -EINVAL) {
dev_err(&pdev->dev, "unexpected hypervisor error (%d)\n", ret);
return -ENODEV;
}
static int xen_wdt_remove(struct platform_device *dev)
{
/* Stop the timer before we leave */
if (!nowayout)
xen_wdt_stop();
if (watchdog_init_timeout(&xen_wdt_dev, timeout, NULL))
dev_info(&pdev->dev, "timeout value invalid, using %d\n",
xen_wdt_dev.timeout);
watchdog_set_nowayout(&xen_wdt_dev, nowayout);
watchdog_stop_on_reboot(&xen_wdt_dev);
watchdog_stop_on_unregister(&xen_wdt_dev);
ret = devm_watchdog_register_device(&pdev->dev, &xen_wdt_dev);
if (ret) {
dev_err(&pdev->dev, "cannot register watchdog device (%d)\n",
ret);
return ret;
}
misc_deregister(&xen_wdt_miscdev);
dev_info(&pdev->dev, "initialized (timeout=%ds, nowayout=%d)\n",
xen_wdt_dev.timeout, nowayout);
return 0;
}
static void xen_wdt_shutdown(struct platform_device *dev)
{
xen_wdt_stop();
}
static int xen_wdt_suspend(struct platform_device *dev, pm_message_t state)
{
typeof(wdt.id) id = wdt.id;
int rc = xen_wdt_stop();
int rc = xen_wdt_stop(&xen_wdt_dev);
wdt.id = id;
return rc;
......@@ -310,13 +169,11 @@ static int xen_wdt_resume(struct platform_device *dev)
if (!wdt.id)
return 0;
wdt.id = 0;
return xen_wdt_start();
return xen_wdt_start(&xen_wdt_dev);
}
static struct platform_driver xen_wdt_driver = {
.probe = xen_wdt_probe,
.remove = xen_wdt_remove,
.shutdown = xen_wdt_shutdown,
.suspend = xen_wdt_suspend,
.resume = xen_wdt_resume,
.driver = {
......@@ -331,8 +188,6 @@ static int __init xen_wdt_init_module(void)
if (!xen_domain())
return -ENODEV;
pr_info("Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
err = platform_driver_register(&xen_wdt_driver);
if (err)
return err;
......@@ -351,7 +206,6 @@ static void __exit xen_wdt_cleanup_module(void)
{
platform_device_unregister(platform_device);
platform_driver_unregister(&xen_wdt_driver);
pr_info("module unloaded\n");
}
module_init(xen_wdt_init_module);
......@@ -359,5 +213,4 @@ module_exit(xen_wdt_cleanup_module);
MODULE_AUTHOR("Jan Beulich <jbeulich@novell.com>");
MODULE_DESCRIPTION("Xen WatchDog Timer Driver");
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment