Commit 5ecf3e11 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull watchdog updates from Wim Van Sebroeck:

 - Add Armada 37xx CPU watchdog

 - w83627hf_wdt: Add Support for NCT6796D, NCT6797D, NCT6798D

 - hpwdt: several improvements

 - renesas_wdt: SPDX identifiers, stop when unregistering, support for
   R7S9210

 - rza_wdt: SPDX identifiers, support longer timeouts

 - core: fix null pointer dereference when releasing cdev

 - iTCO_wdt: Drop option vendorsupport=2

 - sama5d4: fix timeout-sec usage

 - lantiq_wdt: convert to watchdog framework

 - several small fixes

* tag 'linux-watchdog-4.20-rc1' of git://www.linux-watchdog.org/linux-watchdog: (30 commits)
  watchdog: ts4800: release syscon device node in ts4800_wdt_probe()
  watchdog: armada_37xx_wdt: use do_div for u64 division
  documentation: watchdog: add documentation for armada-37xx-wdt
  dt-bindings: watchdog: Document armada-37xx-wdt binding
  watchdog: Add support for Armada 37xx CPU watchdog
  dt-bindings: watchdog: add mpc8xxx-wdt support
  watchdog: mpc8xxx: provide boot status
  MAINTAINERS: Fix file pattern for MEN Z069 watchdog driver
  dt-bindings: watchdog: renesas-wdt: Add support for R7S9210
  watchdog: rza_wdt: Support longer timeouts
  watchdog: hpwdt: Disable PreTimeout when Timeout is smaller
  watchdog: w83627hf_wdt: Support NCT6796D, NCT6797D, NCT6798D
  watchdog: mpc8xxx: use dev_xxxx() instead of pr_xxxx()
  watchdog: lantiq: add get_timeleft callback
  watchdog: lantiq: Convert to watchdog_device
  watchdog: lantiq: update register names to better match spec
  watchdog: sama5d4: fix timeout-sec usage
  watchdog: fix a small number of "watchog" typos in comments
  watchdog: rza_wdt: convert to SPDX identifiers
  watchdog: iTCO_wdt: Remove unused hooks
  ...
parents ed3f4e23 cd6ba41c
* Armada 37xx CPU Watchdog Timer Controller
Required properties:
- compatible : must be "marvell,armada-3700-wdt"
- reg : base physical address of the controller and length of memory mapped
region.
- clocks : the clock feeding the watchdog timer. See clock-bindings.txt
- marvell,system-controller : reference to syscon node for the CPU Miscellaneous
Registers
Example:
cpu_misc: system-controller@d000 {
compatible = "marvell,armada-3700-cpu-misc", "syscon";
reg = <0xd000 0x1000>;
};
wdt: watchdog@8300 {
compatible = "marvell,armada-3700-wdt";
reg = <0x8300 0x40>;
marvell,system-controller = <&cpu_misc>;
clocks = <&xtalclk>;
};
* Freescale mpc8xxx watchdog driver (For 83xx, 86xx and 8xx)
Required properties:
- compatible: Shall contain one of the following:
"mpc83xx_wdt" for an mpc83xx
"fsl,mpc8610-wdt" for an mpc86xx
"fsl,mpc823-wdt" for an mpc8xx
- reg: base physical address and length of the area hosting the
watchdog registers.
On the 83xx, "Watchdog Timer Registers" area: <0x200 0x100>
On the 86xx, "Watchdog Timer Registers" area: <0xe4000 0x100>
On the 8xx, "General System Interface Unit" area: <0x0 0x10>
Optional properties:
- reg: additional physical address and length (4) of location of the
Reset Status Register (called RSTRSCR on the mpc86xx)
On the 83xx, it is located at offset 0x910
On the 86xx, it is located at offset 0xe0094
On the 8xx, it is located at offset 0x288
Example:
WDT: watchdog@0 {
compatible = "fsl,mpc823-wdt";
reg = <0x0 0x10 0x288 0x4>;
};
......@@ -21,6 +21,7 @@ Required properties:
- "renesas,r8a77990-wdt" (R-Car E3)
- "renesas,r8a77995-wdt" (R-Car D3)
- "renesas,r7s72100-wdt" (RZ/A1)
- "renesas,r7s9210-wdt" (RZ/A2)
The generic compatible string must be:
- "renesas,rza-wdt" for RZ/A
- "renesas,rcar-gen2-wdt" for R-Car Gen2 and RZ/G1
......
Last reviewed: 05/20/2016
Last reviewed: 08/20/2018
HPE iLO NMI Watchdog Driver
NMI sourcing for iLO based ProLiant Servers
Documentation and Driver by
Thomas Mingarelli
for iLO based ProLiant Servers
The HPE iLO NMI Watchdog driver is a kernel module that provides basic
watchdog functionality and the added benefit of NMI sourcing. Both the
watchdog functionality and the NMI sourcing capability need to be enabled
by the user. Remember that the two modes are not dependent on one another.
A user can have the NMI sourcing without the watchdog timer and vice-versa.
watchdog functionality and handler for the iLO "Generate NMI to System"
virtual button.
All references to iLO in this document imply it also works on iLO2 and all
subsequent generations.
......@@ -21,12 +18,16 @@ Last reviewed: 05/20/2016
not be updated in a timely fashion and a hardware system reset (also known as
an Automatic Server Recovery (ASR)) event will occur.
The hpwdt driver also has three (3) module parameters. They are the following:
The hpwdt driver also has the following module parameters:
soft_margin - allows the user to set the watchdog timer value.
Default value is 30 seconds.
allow_kdump - allows the user to save off a kernel dump image after an NMI.
Default value is 1/ON
timeout - an alias of soft_margin.
pretimeout - allows the user to set the watchdog pretimeout value.
This is the number of seconds before timeout when an
NMI is delivered to the system. Setting the value to
zero disables the pretimeout NMI.
Default value is 9 seconds.
nowayout - basic watchdog parameter that does not allow the timer to
be restarted or an impending ASR to be escaped.
Default value is set when compiling the kernel. If it is set
......@@ -37,61 +38,29 @@ Last reviewed: 05/20/2016
interface to /dev/watchdog can be found in
Documentation/watchdog/watchdog-api.txt and Documentation/IPMI.txt.
The NMI sourcing capability is disabled by default due to the inability to
distinguish between "NMI Watchdog Ticks" and "HW generated NMI events" in the
Linux kernel. What this means is that the hpwdt nmi handler code is called
each time the NMI signal fires off. This could amount to several thousands of
NMIs in a matter of seconds. If a user sees the Linux kernel's "dazed and
confused" message in the logs or if the system gets into a hung state, then
the hpwdt driver can be reloaded.
1. If the kernel has not been booted with nmi_watchdog turned off then
edit and place the nmi_watchdog=0 at the end of the currently booting
kernel line. Depending on your Linux distribution and platform setup:
For non-UEFI systems
/boot/grub/grub.conf or
/boot/grub/menu.lst
For UEFI systems
/boot/efi/EFI/distroname/grub.conf or
/boot/efi/efi/distroname/elilo.conf
2. reboot the sever
3. Once the system comes up perform a modprobe -r hpwdt
4. modprobe /lib/modules/`uname -r`/kernel/drivers/watchdog/hpwdt.ko
Now, the hpwdt can successfully receive and source the NMI and provide a log
message that details the reason for the NMI (as determined by the HPE BIOS).
Below is a list of NMIs the HPE BIOS understands along with the associated
code (reason):
No source found 00h
Uncorrectable Memory Error 01h
ASR NMI 1Bh
PCI Parity Error 20h
NMI Button Press 27h
SB_BUS_NMI 28h
ILO Doorbell NMI 29h
ILO IOP NMI 2Ah
ILO Watchdog NMI 2Bh
Proc Throt NMI 2Ch
Due to limitations in the iLO hardware, the NMI pretimeout if enabled,
can only be set to 9 seconds. Attempts to set pretimeout to other
non-zero values will be rounded, possibly to zero. Users should verify
the pretimeout value after attempting to set pretimeout or timeout.
Front Side Bus NMI 2Dh
Upon receipt of an NMI from the iLO, the hpwdt driver will initiate a
panic. This is to allow for a crash dump to be collected. It is incumbent
upon the user to have properly configured the system for kdump.
PCI Express Error 2Fh
The default Linux kernel behavior upon panic is to print a kernel tombstone
and loop forever. This is generally not what a watchdog user wants.
DMA controller NMI 30h
For those wishing to learn more please see:
Documentation/kdump/kdump.txt
Documentation/admin-guide/kernel-parameters.txt (panic=)
Your Linux Distribution specific documentation.
Hypertransport/CSI Error 31h
If the hpwdt does not receive the NMI associated with an expiring timer,
the iLO will proceed to reset the system at timeout if the timer hasn't
been updated.
--
The HPE iLO NMI Watchdog Driver and documentation were originally developed
by Tom Mingarelli.
-- Tom Mingarelli
......@@ -40,6 +40,11 @@ margin: Watchdog margin in seconds (default=60)
nowayout: Disable watchdog shutdown on close
(default=kernel config parameter)
-------------------------------------------------
armada_37xx_wdt:
timeout: Watchdog timeout in seconds. (default=120)
nowayout: Disable watchdog shutdown on close
(default=kernel config parameter)
-------------------------------------------------
at91rm9200_wdt:
wdt_time: Watchdog time in seconds. (default=5)
nowayout: Watchdog cannot be stopped once started
......
......@@ -9568,7 +9568,7 @@ MEN Z069 WATCHDOG DRIVER
M: Johannes Thumshirn <jth@kernel.org>
L: linux-watchdog@vger.kernel.org
S: Maintained
F: drivers/watchdog/menz069_wdt.c
F: drivers/watchdog/menz69_wdt.c
MESON AO CEC DRIVER FOR AMLOGIC SOCS
M: Neil Armstrong <narmstrong@baylibre.com>
......
......@@ -273,6 +273,17 @@ config ARM_SBSA_WATCHDOG
To compile this driver as module, choose M here: The module
will be called sbsa_gwdt.
config ARMADA_37XX_WATCHDOG
tristate "Armada 37xx watchdog"
depends on ARCH_MVEBU || COMPILE_TEST
select MFD_SYSCON
select WATCHDOG_CORE
help
Say Y here to include support for the watchdog timer found on
Marvell Armada 37xx SoCs.
To compile this driver as a module, choose M here: the
module will be called armada_37xx_wdt.
config ASM9260_WATCHDOG
tristate "Alphascale ASM9260 watchdog"
depends on MACH_ASM9260 || COMPILE_TEST
......@@ -1621,6 +1632,7 @@ config IMGPDC_WDT
config LANTIQ_WDT
tristate "Lantiq SoC watchdog"
depends on LANTIQ
select WATCHDOG_CORE
help
Hardware driver for the Lantiq SoC Watchdog Timer.
......
......@@ -38,6 +38,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
# ARM Architecture
obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
obj-$(CONFIG_ARM_SBSA_WATCHDOG) += sbsa_gwdt.o
obj-$(CONFIG_ARMADA_37XX_WATCHDOG) += armada_37xx_wdt.o
obj-$(CONFIG_ASM9260_WATCHDOG) += asm9260_wdt.o
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
......
This diff is collapsed.
......@@ -25,7 +25,7 @@
/* If the kernel parameter wdt=1, the watchdog will be enabled at boot.
* Also, the wdt_period sets the watchdog timer period timeout.
* For E500 cpus the wdt_period sets which bit changing from 0->1 will
* trigger a watchog timeout. This watchdog timeout will occur 3 times, the
* trigger a watchdog timeout. This watchdog timeout will occur 3 times, the
* first time nothing will happen, the second time a watchdog exception will
* occur, and the final time the board will reset.
*/
......
......@@ -26,7 +26,7 @@
#include <linux/watchdog.h>
#include <asm/nmi.h>
#define HPWDT_VERSION "2.0.0"
#define HPWDT_VERSION "2.0.1"
#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
......@@ -162,7 +162,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
if (ilo5 && ulReason == NMI_UNKNOWN && !mynmi)
return NMI_DONE;
if (ilo5 && !pretimeout)
if (ilo5 && !pretimeout && !mynmi)
return NMI_DONE;
hpwdt_stop();
......@@ -205,9 +205,7 @@ static struct watchdog_device hpwdt_dev = {
.min_timeout = 1,
.max_timeout = HPWDT_MAX_TIMER,
.timeout = DEFAULT_MARGIN,
#ifdef CONFIG_HPWDT_NMI_DECODING
.pretimeout = PRETIMEOUT_SEC,
#endif
};
......@@ -313,6 +311,12 @@ static int hpwdt_init_one(struct pci_dev *dev,
if (watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL))
dev_warn(&dev->dev, "Invalid soft_margin: %d.\n", soft_margin);
if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
pretimeout = 0;
}
hpwdt_dev.pretimeout = pretimeout ? PRETIMEOUT_SEC : 0;
hpwdt_dev.parent = &dev->dev;
retval = watchdog_register_device(&hpwdt_dev);
if (retval < 0) {
......@@ -320,9 +324,12 @@ static int hpwdt_init_one(struct pci_dev *dev,
goto error_wd_register;
}
dev_info(&dev->dev, "HPE Watchdog Timer Driver: %s"
", timer margin: %d seconds (nowayout=%d).\n",
HPWDT_VERSION, hpwdt_dev.timeout, nowayout);
dev_info(&dev->dev, "HPE Watchdog Timer Driver: Version: %s\n",
HPWDT_VERSION);
dev_info(&dev->dev, "timeout: %d seconds (nowayout=%d)\n",
hpwdt_dev.timeout, nowayout);
dev_info(&dev->dev, "pretimeout: %s.\n",
pretimeout ? "on" : "off");
if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
ilo5 = true;
......@@ -364,6 +371,9 @@ MODULE_VERSION(HPWDT_VERSION);
module_param(soft_margin, int, 0);
MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
module_param_named(timeout, soft_margin, int, 0);
MODULE_PARM_DESC(timeout, "Alias of soft_margin");
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
......
......@@ -3,14 +3,10 @@
#ifdef CONFIG_ITCO_VENDOR_SUPPORT
extern void iTCO_vendor_pre_start(struct resource *, unsigned int);
extern void iTCO_vendor_pre_stop(struct resource *);
extern void iTCO_vendor_pre_keepalive(struct resource *, unsigned int);
extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
extern int iTCO_vendor_check_noreboot_on(void);
#else
#define iTCO_vendor_pre_start(acpibase, heartbeat) {}
#define iTCO_vendor_pre_stop(acpibase) {}
#define iTCO_vendor_pre_keepalive(acpibase, heartbeat) {}
#define iTCO_vendor_pre_set_heartbeat(heartbeat) {}
#define iTCO_vendor_check_noreboot_on() 1
/* 1=check noreboot; 0=don't check */
#endif
......@@ -38,7 +38,7 @@
/* List of vendor support modes */
/* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
#define SUPERMICRO_OLD_BOARD 1
/* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */
/* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems - no longer supported */
#define SUPERMICRO_NEW_BOARD 2
/* Broken BIOS */
#define BROKEN_BIOS 911
......@@ -46,8 +46,7 @@
static int vendorsupport;
module_param(vendorsupport, int, 0);
MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
"0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+, "
"911=Broken SMI BIOS");
"0 (none), 1=SuperMicro Pent3, 911=Broken SMI BIOS");
/*
* Vendor Specific Support
......@@ -97,143 +96,6 @@ static void supermicro_old_pre_stop(struct resource *smires)
outl(val32, smires->start); /* Needed to deactivate watchdog */
}
/*
* Vendor Support: 2
* Board: Super Micro Computer Inc. P4SBx, P4DPx
* iTCO chipset: ICH4
*
* Code contributed by: R. Seretny <lkpatches@paypc.com>
* Documentation obtained by R. Seretny from SuperMicro Technical Support
*
* To enable Watchdog function:
* 1. BIOS
* For P4SBx:
* BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature
* For P4DPx:
* BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog
* This setting enables or disables Watchdog function. When enabled, the
* default watchdog timer is set to be 5 minutes (about 4m35s). It is
* enough to load and run the OS. The application (service or driver) has
* to take over the control once OS is running up and before watchdog
* expires.
*
* 2. JUMPER
* For P4SBx: JP39
* For P4DPx: JP37
* This jumper is used for safety. Closed is enabled. This jumper
* prevents user enables watchdog in BIOS by accident.
*
* To enable Watch Dog function, both BIOS and JUMPER must be enabled.
*
* The documentation lists motherboards P4SBx and P4DPx series as of
* 20-March-2002. However, this code works flawlessly with much newer
* motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82).
*
* The original iTCO driver as written does not actually reset the
* watchdog timer on these machines, as a result they reboot after five
* minutes.
*
* NOTE: You may leave the Watchdog function disabled in the SuperMicro
* BIOS to avoid a "boot-race"... This driver will enable watchdog
* functionality even if it's disabled in the BIOS once the /dev/watchdog
* file is opened.
*/
/* I/O Port's */
#define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */
#define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */
/* Control Register's */
#define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */
#define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */
#define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */
#define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */
#define SM_ENDWATCH 0xAA /* Watchdog lock control page */
#define SM_COUNTMODE 0xf5 /* Watchdog count mode select */
/* (Bit 3: 0 = seconds, 1 = minutes */
#define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */
#define SM_RESETCONTROL 0xf7 /* Watchdog reset control */
/* Bit 6: timer is reset by kbd interrupt */
/* Bit 7: timer is reset by mouse interrupt */
static void supermicro_new_unlock_watchdog(void)
{
/* Write 0x87 to port 0x2e twice */
outb(SM_WATCHPAGE, SM_REGINDEX);
outb(SM_WATCHPAGE, SM_REGINDEX);
/* Switch to watchdog control page */
outb(SM_CTLPAGESW, SM_REGINDEX);
outb(SM_CTLPAGE, SM_DATAIO);
}
static void supermicro_new_lock_watchdog(void)
{
outb(SM_ENDWATCH, SM_REGINDEX);
}
static void supermicro_new_pre_start(unsigned int heartbeat)
{
unsigned int val;
supermicro_new_unlock_watchdog();
/* Watchdog timer setting needs to be in seconds*/
outb(SM_COUNTMODE, SM_REGINDEX);
val = inb(SM_DATAIO);
val &= 0xF7;
outb(val, SM_DATAIO);
/* Write heartbeat interval to WDOG */
outb(SM_WATCHTIMER, SM_REGINDEX);
outb((heartbeat & 255), SM_DATAIO);
/* Make sure keyboard/mouse interrupts don't interfere */
outb(SM_RESETCONTROL, SM_REGINDEX);
val = inb(SM_DATAIO);
val &= 0x3f;
outb(val, SM_DATAIO);
/* enable watchdog by setting bit 0 of Watchdog Enable to 1 */
outb(SM_WATCHENABLE, SM_REGINDEX);
val = inb(SM_DATAIO);
val |= 0x01;
outb(val, SM_DATAIO);
supermicro_new_lock_watchdog();
}
static void supermicro_new_pre_stop(void)
{
unsigned int val;
supermicro_new_unlock_watchdog();
/* disable watchdog by setting bit 0 of Watchdog Enable to 0 */
outb(SM_WATCHENABLE, SM_REGINDEX);
val = inb(SM_DATAIO);
val &= 0xFE;
outb(val, SM_DATAIO);
supermicro_new_lock_watchdog();
}
static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
{
supermicro_new_unlock_watchdog();
/* reset watchdog timeout to heartveat value */
outb(SM_WATCHTIMER, SM_REGINDEX);
outb((heartbeat & 255), SM_DATAIO);
supermicro_new_lock_watchdog();
}
/*
* Vendor Support: 911
* Board: Some Intel ICHx based motherboards
......@@ -298,9 +160,6 @@ void iTCO_vendor_pre_start(struct resource *smires,
case SUPERMICRO_OLD_BOARD:
supermicro_old_pre_start(smires);
break;
case SUPERMICRO_NEW_BOARD:
supermicro_new_pre_start(heartbeat);
break;
case BROKEN_BIOS:
broken_bios_start(smires);
break;
......@@ -314,9 +173,6 @@ void iTCO_vendor_pre_stop(struct resource *smires)
case SUPERMICRO_OLD_BOARD:
supermicro_old_pre_stop(smires);
break;
case SUPERMICRO_NEW_BOARD:
supermicro_new_pre_stop();
break;
case BROKEN_BIOS:
broken_bios_stop(smires);
break;
......@@ -324,20 +180,6 @@ void iTCO_vendor_pre_stop(struct resource *smires)
}
EXPORT_SYMBOL(iTCO_vendor_pre_stop);
void iTCO_vendor_pre_keepalive(struct resource *smires, unsigned int heartbeat)
{
if (vendorsupport == SUPERMICRO_NEW_BOARD)
supermicro_new_pre_set_heartbeat(heartbeat);
}
EXPORT_SYMBOL(iTCO_vendor_pre_keepalive);
void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat)
{
if (vendorsupport == SUPERMICRO_NEW_BOARD)
supermicro_new_pre_set_heartbeat(heartbeat);
}
EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
int iTCO_vendor_check_noreboot_on(void)
{
switch (vendorsupport) {
......@@ -351,6 +193,12 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
static int __init iTCO_vendor_init_module(void)
{
if (vendorsupport == SUPERMICRO_NEW_BOARD) {
pr_warn("Option vendorsupport=%d is no longer supported, "
"please use the w83627hf_wdt driver instead\n",
SUPERMICRO_NEW_BOARD);
return -EINVAL;
}
pr_info("vendor-support=%d\n", vendorsupport);
return 0;
}
......
......@@ -304,8 +304,6 @@ static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
spin_lock(&p->io_lock);
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));
......@@ -342,8 +340,6 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
(p->iTCO_version == 1 && tmrval > 0x03f))
return -EINVAL;
iTCO_vendor_pre_set_heartbeat(tmrval);
/* Write new heartbeat to watchdog */
if (p->iTCO_version >= 2) {
spin_lock(&p->io_lock);
......
This diff is collapsed.
......@@ -17,8 +17,6 @@
* option) any later version.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
......@@ -49,6 +47,7 @@ struct mpc8xxx_wdt {
struct mpc8xxx_wdt_type {
int prescaler;
bool hw_enabled;
u32 rsr_mask;
};
struct mpc8xxx_wdt_ddata {
......@@ -137,36 +136,55 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
struct mpc8xxx_wdt_ddata *ddata;
u32 freq = fsl_get_sys_freq();
bool enabled;
struct device *dev = &ofdev->dev;
wdt_type = of_device_get_match_data(&ofdev->dev);
wdt_type = of_device_get_match_data(dev);
if (!wdt_type)
return -EINVAL;
if (!freq || freq == -1)
return -EINVAL;
ddata = devm_kzalloc(&ofdev->dev, sizeof(*ddata), GFP_KERNEL);
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
ddata->base = devm_ioremap_resource(&ofdev->dev, res);
ddata->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ddata->base))
return PTR_ERR(ddata->base);
enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN;
if (!enabled && wdt_type->hw_enabled) {
pr_info("could not be enabled in software\n");
dev_info(dev, "could not be enabled in software\n");
return -ENODEV;
}
res = platform_get_resource(ofdev, IORESOURCE_MEM, 1);
if (res) {
bool status;
u32 __iomem *rsr = ioremap(res->start, resource_size(res));
if (!rsr)
return -ENOMEM;
status = in_be32(rsr) & wdt_type->rsr_mask;
ddata->wdd.bootstatus = status ? WDIOF_CARDRESET : 0;
/* clear reset status bits related to watchdog timer */
out_be32(rsr, wdt_type->rsr_mask);
iounmap(rsr);
dev_info(dev, "Last boot was %scaused by watchdog\n",
status ? "" : "not ");
}
spin_lock_init(&ddata->lock);
ddata->wdd.info = &mpc8xxx_wdt_info,
ddata->wdd.ops = &mpc8xxx_wdt_ops,
ddata->wdd.timeout = WATCHDOG_TIMEOUT;
watchdog_init_timeout(&ddata->wdd, timeout, &ofdev->dev);
watchdog_init_timeout(&ddata->wdd, timeout, dev);
watchdog_set_nowayout(&ddata->wdd, nowayout);
......@@ -189,12 +207,13 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
ret = watchdog_register_device(&ddata->wdd);
if (ret) {
pr_err("cannot register watchdog device (err=%d)\n", ret);
dev_err(dev, "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);
dev_info(dev,
"WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n",
reset ? "reset" : "interrupt", ddata->wdd.timeout);
platform_set_drvdata(ofdev, ddata);
return 0;
......@@ -204,8 +223,8 @@ static int mpc8xxx_wdt_remove(struct platform_device *ofdev)
{
struct mpc8xxx_wdt_ddata *ddata = platform_get_drvdata(ofdev);
pr_crit("Watchdog removed, expect the %s soon!\n",
reset ? "reset" : "machine check exception");
dev_crit(&ofdev->dev, "Watchdog removed, expect the %s soon!\n",
reset ? "reset" : "machine check exception");
watchdog_unregister_device(&ddata->wdd);
return 0;
......@@ -216,6 +235,7 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
.compatible = "mpc83xx_wdt",
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x10000,
.rsr_mask = BIT(3), /* RSR Bit SWRS */
},
},
{
......@@ -223,6 +243,7 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x10000,
.hw_enabled = true,
.rsr_mask = BIT(20), /* RSTRSCR Bit WDT_RR */
},
},
{
......@@ -230,6 +251,7 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x800,
.hw_enabled = true,
.rsr_mask = BIT(28), /* RSR Bit SWRS */
},
},
{},
......
// SPDX-License-Identifier: GPL-2.0
/*
* Watchdog driver for Renesas WDT watchdog
*
* Copyright (C) 2015-17 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
* Copyright (C) 2015-17 Renesas Electronics Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/bitops.h>
#include <linux/clk.h>
......@@ -234,6 +231,7 @@ static int rwdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(&priv->wdev, priv);
watchdog_set_nowayout(&priv->wdev, nowayout);
watchdog_set_restart_priority(&priv->wdev, 0);
watchdog_stop_on_unregister(&priv->wdev);
/* This overrides the default timeout only if DT configuration was found */
ret = watchdog_init_timeout(&priv->wdev, 0, &pdev->dev);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Renesas RZ/A Series WDT Driver
*
* Copyright (C) 2017 Renesas Electronics America, Inc.
* Copyright (C) 2017 Chris Brandt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/bitops.h>
......@@ -14,6 +11,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
......@@ -34,12 +32,45 @@
#define WRCSR_RSTE BIT(6)
#define WRCSR_CLEAR_WOVF 0xA500 /* special value */
/* The maximum CKS register setting value to get the longest timeout */
#define CKS_3BIT 0x7
#define CKS_4BIT 0xF
#define DIVIDER_3BIT 16384 /* Clock divider when CKS = 0x7 */
#define DIVIDER_4BIT 4194304 /* Clock divider when CKS = 0xF */
struct rza_wdt {
struct watchdog_device wdev;
void __iomem *base;
struct clk *clk;
u8 count;
u8 cks;
};
static void rza_wdt_calc_timeout(struct rza_wdt *priv, int timeout)
{
unsigned long rate = clk_get_rate(priv->clk);
unsigned int ticks;
if (priv->cks == CKS_4BIT) {
ticks = DIV_ROUND_UP(timeout * rate, DIVIDER_4BIT);
/*
* Since max_timeout was set in probe, we know that the timeout
* value passed will never calculate to a tick value greater
* than 256.
*/
priv->count = 256 - ticks;
} else {
/* Start timer with longest timeout */
priv->count = 0;
}
pr_debug("%s: timeout set to %u (WTCNT=%d)\n", __func__,
timeout, priv->count);
}
static int rza_wdt_start(struct watchdog_device *wdev)
{
struct rza_wdt *priv = watchdog_get_drvdata(wdev);
......@@ -51,13 +82,12 @@ static int rza_wdt_start(struct watchdog_device *wdev)
readb(priv->base + WRCSR);
writew(WRCSR_CLEAR_WOVF, priv->base + WRCSR);
/*
* Start timer with slowest clock source and reset option enabled.
*/
rza_wdt_calc_timeout(priv, wdev->timeout);
writew(WRCSR_MAGIC | WRCSR_RSTE, priv->base + WRCSR);
writew(WTCNT_MAGIC | 0, priv->base + WTCNT);
writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME | WTSCR_CKS(7),
priv->base + WTCSR);
writew(WTCNT_MAGIC | priv->count, priv->base + WTCNT);
writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME |
WTSCR_CKS(priv->cks), priv->base + WTCSR);
return 0;
}
......@@ -75,8 +105,17 @@ static int rza_wdt_ping(struct watchdog_device *wdev)
{
struct rza_wdt *priv = watchdog_get_drvdata(wdev);
writew(WTCNT_MAGIC | 0, priv->base + WTCNT);
writew(WTCNT_MAGIC | priv->count, priv->base + WTCNT);
pr_debug("%s: timeout = %u\n", __func__, wdev->timeout);
return 0;
}
static int rza_set_timeout(struct watchdog_device *wdev, unsigned int timeout)
{
wdev->timeout = timeout;
rza_wdt_start(wdev);
return 0;
}
......@@ -121,6 +160,7 @@ static const struct watchdog_ops rza_wdt_ops = {
.start = rza_wdt_start,
.stop = rza_wdt_stop,
.ping = rza_wdt_ping,
.set_timeout = rza_set_timeout,
.restart = rza_wdt_restart,
};
......@@ -150,20 +190,28 @@ static int rza_wdt_probe(struct platform_device *pdev)
return -ENOENT;
}
/* Assume slowest clock rate possible (CKS=7) */
rate /= 16384;
priv->wdev.info = &rza_wdt_ident,
priv->wdev.ops = &rza_wdt_ops,
priv->wdev.parent = &pdev->dev;
/*
* Since the max possible timeout of our 8-bit count register is less
* than a second, we must use max_hw_heartbeat_ms.
*/
priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate;
dev_dbg(&pdev->dev, "max hw timeout of %dms\n",
priv->wdev.max_hw_heartbeat_ms);
priv->cks = (u8)(uintptr_t)of_device_get_match_data(&pdev->dev);
if (priv->cks == CKS_4BIT) {
/* Assume slowest clock rate possible (CKS=0xF) */
priv->wdev.max_timeout = (DIVIDER_4BIT * U8_MAX) / rate;
} else if (priv->cks == CKS_3BIT) {
/* Assume slowest clock rate possible (CKS=7) */
rate /= DIVIDER_3BIT;
/*
* Since the max possible timeout of our 8-bit count
* register is less than a second, we must use
* max_hw_heartbeat_ms.
*/
priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate;
dev_dbg(&pdev->dev, "max hw timeout of %dms\n",
priv->wdev.max_hw_heartbeat_ms);
}
priv->wdev.min_timeout = 1;
priv->wdev.timeout = DEFAULT_TIMEOUT;
......@@ -179,7 +227,8 @@ static int rza_wdt_probe(struct platform_device *pdev)
}
static const struct of_device_id rza_wdt_of_match[] = {
{ .compatible = "renesas,rza-wdt", },
{ .compatible = "renesas,r7s9210-wdt", .data = (void *)CKS_4BIT, },
{ .compatible = "renesas,rza-wdt", .data = (void *)CKS_3BIT, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rza_wdt_of_match);
......
......@@ -247,11 +247,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
}
}
ret = watchdog_init_timeout(wdd, wdt_timeout, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "unable to set timeout value\n");
return ret;
}
watchdog_init_timeout(wdd, wdt_timeout, &pdev->dev);
timeout = WDT_SEC2TICKS(wdd->timeout);
......
......@@ -135,6 +135,7 @@ static int ts4800_wdt_probe(struct platform_device *pdev)
/* set regmap and offset to know where to write */
wdt->feed_offset = reg;
wdt->regmap = syscon_node_to_regmap(syscon_np);
of_node_put(syscon_np);
if (IS_ERR(wdt->regmap)) {
dev_err(&pdev->dev, "cannot get parent's regmap\n");
return PTR_ERR(wdt->regmap);
......
......@@ -30,7 +30,7 @@
#define VIA_WDT_CONF_MMIO 0x02 /* 1: enable watchdog MMIO */
/*
* The MMIO region contains the watchog control register and the
* The MMIO region contains the watchdog control register and the
* hardware timer counter.
*/
#define VIA_WDT_MMIO_LEN 8 /* MMIO region length in bytes */
......@@ -82,7 +82,7 @@ static inline void wdt_reset(void)
/*
* Timer tick: the timer will make sure that the watchdog timer hardware
* is being reset in time. The conditions to do this are:
* 1) the watchog timer has been started and /dev/watchdog is open
* 1) the watchdog timer has been started and /dev/watchdog is open
* and there is still time left before userspace should send the
* next heartbeat/ping. (note: the internal heartbeat is much smaller
* then the external/userspace heartbeat).
......
......@@ -50,7 +50,7 @@ static int cr_wdt_csr; /* WDT control & status register */
enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p,
w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
nct6795, nct6102 };
nct6795, nct6796, nct6102 };
static int timeout; /* in seconds */
module_param(timeout, int, 0);
......@@ -100,6 +100,7 @@ MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)");
#define NCT6792_ID 0xc9
#define NCT6793_ID 0xd1
#define NCT6795_ID 0xd3
#define NCT6796_ID 0xd4 /* also NCT9697D, NCT9698D */
#define W83627HF_WDT_TIMEOUT 0xf6
#define W83697HF_WDT_TIMEOUT 0xf4
......@@ -209,6 +210,7 @@ static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
case nct6792:
case nct6793:
case nct6795:
case nct6796:
case nct6102:
/*
* These chips have a fixed WDTO# output pin (W83627UHG),
......@@ -407,6 +409,9 @@ static int wdt_find(int addr)
case NCT6795_ID:
ret = nct6795;
break;
case NCT6796_ID:
ret = nct6796;
break;
case NCT6102_ID:
ret = nct6102;
cr_wdt_timeout = NCT6102D_WDT_TIMEOUT;
......@@ -450,6 +455,7 @@ static int __init wdt_init(void)
"NCT6792",
"NCT6793",
"NCT6795",
"NCT6796",
"NCT6102",
};
......
......@@ -1019,16 +1019,16 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
old_wd_data = NULL;
}
mutex_lock(&wd_data->lock);
wd_data->wdd = NULL;
wdd->wd_data = NULL;
mutex_unlock(&wd_data->lock);
if (watchdog_active(wdd) &&
test_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status)) {
watchdog_stop(wdd);
}
mutex_lock(&wd_data->lock);
wd_data->wdd = NULL;
wdd->wd_data = NULL;
mutex_unlock(&wd_data->lock);
hrtimer_cancel(&wd_data->timer);
kthread_cancel_work_sync(&wd_data->work);
......
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