Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog: [WATCHDOG] removed unused #include <version.h> [WATCHDOG] at91rm9200_wdt.c: fix misleading indentation [WATCHDOG] mpc8xxx_wdt: fix modular build [WATCHDOG] hpwdt.c kdebug support [WATCHDOG] Add support for the IDT RC32434 watchdog [WATCHDOG] Add support for the built-int RDC R-321x SoC watchdog [WATHDOG] delete unused driver mpc8xx_wdt.c [WATCHDOG] Fix s3c2410_wdt driver coding style issues [WATCHDOG] Clean out header of s3c2410_wdt driver. [WATCHDOG] Fix NULL usage in s3c2410_wdt driver.
This commit is contained in:
commit
ee7cbabbd3
|
@ -465,6 +465,16 @@ config PC87413_WDT
|
||||||
|
|
||||||
Most people will say N.
|
Most people will say N.
|
||||||
|
|
||||||
|
config RDC321X_WDT
|
||||||
|
tristate "RDC R-321x SoC watchdog"
|
||||||
|
depends on X86_RDC321X
|
||||||
|
help
|
||||||
|
This is the driver for the built in hardware watchdog
|
||||||
|
in the RDC R-321x SoC.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called rdc321x_wdt.
|
||||||
|
|
||||||
config 60XX_WDT
|
config 60XX_WDT
|
||||||
tristate "SBC-60XX Watchdog Timer"
|
tristate "SBC-60XX Watchdog Timer"
|
||||||
depends on X86
|
depends on X86
|
||||||
|
@ -633,6 +643,16 @@ config SBC_EPX_C3_WATCHDOG
|
||||||
|
|
||||||
# MIPS Architecture
|
# MIPS Architecture
|
||||||
|
|
||||||
|
config RC32434_WDT
|
||||||
|
tristate "IDT RC32434 SoC Watchdog Timer"
|
||||||
|
depends on MIKROTIK_RB532
|
||||||
|
help
|
||||||
|
Hardware driver for the IDT RC32434 SoC built-in
|
||||||
|
watchdog timer.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called rc32434_wdt.
|
||||||
|
|
||||||
config INDYDOG
|
config INDYDOG
|
||||||
tristate "Indy/I2 Hardware Watchdog"
|
tristate "Indy/I2 Hardware Watchdog"
|
||||||
depends on SGI_HAS_INDYDOG
|
depends on SGI_HAS_INDYDOG
|
||||||
|
@ -692,10 +712,6 @@ config MPC5200_WDT
|
||||||
tristate "MPC5200 Watchdog Timer"
|
tristate "MPC5200 Watchdog Timer"
|
||||||
depends on PPC_MPC52xx
|
depends on PPC_MPC52xx
|
||||||
|
|
||||||
config 8xx_WDT
|
|
||||||
tristate "MPC8xx Watchdog Timer"
|
|
||||||
depends on 8xx
|
|
||||||
|
|
||||||
config 8xxx_WDT
|
config 8xxx_WDT
|
||||||
tristate "MPC8xxx Platform Watchdog Timer"
|
tristate "MPC8xxx Platform Watchdog Timer"
|
||||||
depends on PPC_8xx || PPC_83xx || PPC_86xx
|
depends on PPC_8xx || PPC_83xx || PPC_86xx
|
||||||
|
|
|
@ -75,6 +75,7 @@ obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
|
||||||
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
|
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
|
||||||
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
|
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
|
||||||
obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
|
obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
|
||||||
|
obj-$(CONFIG_RDC321X_WDT) += rdc321x_wdt.o
|
||||||
obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
|
obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
|
||||||
obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
|
obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
|
||||||
obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o
|
obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o
|
||||||
|
@ -94,6 +95,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
|
||||||
# M68KNOMMU Architecture
|
# M68KNOMMU Architecture
|
||||||
|
|
||||||
# MIPS Architecture
|
# MIPS Architecture
|
||||||
|
obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
|
||||||
obj-$(CONFIG_INDYDOG) += indydog.o
|
obj-$(CONFIG_INDYDOG) += indydog.o
|
||||||
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
|
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
|
||||||
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
|
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
|
||||||
|
@ -104,7 +106,6 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
|
||||||
# PARISC Architecture
|
# PARISC Architecture
|
||||||
|
|
||||||
# POWERPC Architecture
|
# POWERPC Architecture
|
||||||
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
|
|
||||||
obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
|
obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
|
||||||
obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o
|
obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o
|
||||||
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
|
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
|
||||||
|
|
|
@ -241,7 +241,7 @@ static int at91wdt_resume(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
if (at91wdt_busy)
|
if (at91wdt_busy)
|
||||||
at91_wdt_start();
|
at91_wdt_start();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -116,6 +116,7 @@ static unsigned int reload; /* the computed soft_margin */
|
||||||
static int nowayout = WATCHDOG_NOWAYOUT;
|
static int nowayout = WATCHDOG_NOWAYOUT;
|
||||||
static char expect_release;
|
static char expect_release;
|
||||||
static unsigned long hpwdt_is_open;
|
static unsigned long hpwdt_is_open;
|
||||||
|
static unsigned int allow_kdump;
|
||||||
|
|
||||||
static void __iomem *pci_mem_addr; /* the PCI-memory address */
|
static void __iomem *pci_mem_addr; /* the PCI-memory address */
|
||||||
static unsigned long __iomem *hpwdt_timer_reg;
|
static unsigned long __iomem *hpwdt_timer_reg;
|
||||||
|
@ -221,19 +222,19 @@ static int __devinit cru_detect(unsigned long map_entry,
|
||||||
|
|
||||||
if (cmn_regs.u1.ral != 0) {
|
if (cmn_regs.u1.ral != 0) {
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
"hpwdt: Call succeeded but with an error: 0x%x\n",
|
"hpwdt: Call succeeded but with an error: 0x%x\n",
|
||||||
cmn_regs.u1.ral);
|
cmn_regs.u1.ral);
|
||||||
} else {
|
} else {
|
||||||
physical_bios_base = cmn_regs.u2.rebx;
|
physical_bios_base = cmn_regs.u2.rebx;
|
||||||
physical_bios_offset = cmn_regs.u4.redx;
|
physical_bios_offset = cmn_regs.u4.redx;
|
||||||
cru_length = cmn_regs.u3.recx;
|
cru_length = cmn_regs.u3.recx;
|
||||||
cru_physical_address =
|
cru_physical_address =
|
||||||
physical_bios_base + physical_bios_offset;
|
physical_bios_base + physical_bios_offset;
|
||||||
|
|
||||||
/* If the values look OK, then map it in. */
|
/* If the values look OK, then map it in. */
|
||||||
if ((physical_bios_base + physical_bios_offset)) {
|
if ((physical_bios_base + physical_bios_offset)) {
|
||||||
cru_rom_addr =
|
cru_rom_addr =
|
||||||
ioremap(cru_physical_address, cru_length);
|
ioremap(cru_physical_address, cru_length);
|
||||||
if (cru_rom_addr)
|
if (cru_rom_addr)
|
||||||
retval = 0;
|
retval = 0;
|
||||||
}
|
}
|
||||||
|
@ -356,7 +357,6 @@ asm(".text \n\t"
|
||||||
"call *%r12 \n\t"
|
"call *%r12 \n\t"
|
||||||
"pushfq \n\t"
|
"pushfq \n\t"
|
||||||
"popq %r12 \n\t"
|
"popq %r12 \n\t"
|
||||||
"popfq \n\t"
|
|
||||||
"movl %eax, (%r9) \n\t"
|
"movl %eax, (%r9) \n\t"
|
||||||
"movl %ebx, 4(%r9) \n\t"
|
"movl %ebx, 4(%r9) \n\t"
|
||||||
"movl %ecx, 8(%r9) \n\t"
|
"movl %ecx, 8(%r9) \n\t"
|
||||||
|
@ -390,10 +390,10 @@ static void __devinit dmi_find_cru(const struct dmi_header *dm)
|
||||||
smbios_cru64_ptr = (struct smbios_cru64_info *) dm;
|
smbios_cru64_ptr = (struct smbios_cru64_info *) dm;
|
||||||
if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) {
|
if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) {
|
||||||
cru_physical_address =
|
cru_physical_address =
|
||||||
smbios_cru64_ptr->physical_address +
|
smbios_cru64_ptr->physical_address +
|
||||||
smbios_cru64_ptr->double_offset;
|
smbios_cru64_ptr->double_offset;
|
||||||
cru_rom_addr = ioremap(cru_physical_address,
|
cru_rom_addr = ioremap(cru_physical_address,
|
||||||
smbios_cru64_ptr->double_length);
|
smbios_cru64_ptr->double_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,41 +405,13 @@ static int __devinit detect_cru_service(void)
|
||||||
dmi_walk(dmi_find_cru);
|
dmi_walk(dmi_find_cru);
|
||||||
|
|
||||||
/* if cru_rom_addr has been set then we found a CRU service */
|
/* if cru_rom_addr has been set then we found a CRU service */
|
||||||
return ((cru_rom_addr != NULL) ? 0: -ENODEV);
|
return ((cru_rom_addr != NULL) ? 0 : -ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* NMI Handler
|
|
||||||
*/
|
|
||||||
static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
unsigned long rom_pl;
|
|
||||||
static int die_nmi_called;
|
|
||||||
|
|
||||||
if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI)
|
|
||||||
return NOTIFY_OK;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&rom_lock, rom_pl);
|
|
||||||
if (!die_nmi_called)
|
|
||||||
asminline_call(&cmn_regs, cru_rom_addr);
|
|
||||||
die_nmi_called = 1;
|
|
||||||
spin_unlock_irqrestore(&rom_lock, rom_pl);
|
|
||||||
if (cmn_regs.u1.ral == 0) {
|
|
||||||
printk(KERN_WARNING "hpwdt: An NMI occurred, "
|
|
||||||
"but unable to determine source.\n");
|
|
||||||
} else {
|
|
||||||
panic("An NMI occurred, please see the Integrated "
|
|
||||||
"Management Log for details.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return NOTIFY_STOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Watchdog operations
|
* Watchdog operations
|
||||||
*/
|
*/
|
||||||
|
@ -483,6 +455,36 @@ static int hpwdt_change_timer(int new_margin)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NMI Handler
|
||||||
|
*/
|
||||||
|
static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
unsigned long rom_pl;
|
||||||
|
static int die_nmi_called;
|
||||||
|
|
||||||
|
if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI)
|
||||||
|
return NOTIFY_OK;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&rom_lock, rom_pl);
|
||||||
|
if (!die_nmi_called)
|
||||||
|
asminline_call(&cmn_regs, cru_rom_addr);
|
||||||
|
die_nmi_called = 1;
|
||||||
|
spin_unlock_irqrestore(&rom_lock, rom_pl);
|
||||||
|
if (cmn_regs.u1.ral == 0) {
|
||||||
|
printk(KERN_WARNING "hpwdt: An NMI occurred, "
|
||||||
|
"but unable to determine source.\n");
|
||||||
|
} else {
|
||||||
|
if (allow_kdump)
|
||||||
|
hpwdt_stop();
|
||||||
|
panic("An NMI occurred, please see the Integrated "
|
||||||
|
"Management Log for details.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOTIFY_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* /dev/watchdog handling
|
* /dev/watchdog handling
|
||||||
*/
|
*/
|
||||||
|
@ -625,17 +627,18 @@ static struct notifier_block die_notifier = {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int __devinit hpwdt_init_one(struct pci_dev *dev,
|
static int __devinit hpwdt_init_one(struct pci_dev *dev,
|
||||||
const struct pci_device_id *ent)
|
const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First let's find out if we are on an iLO2 server. We will
|
* First let's find out if we are on an iLO2 server. We will
|
||||||
* not run on a legacy ASM box.
|
* not run on a legacy ASM box.
|
||||||
|
* So we only support the G5 ProLiant servers and higher.
|
||||||
*/
|
*/
|
||||||
if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) {
|
if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) {
|
||||||
dev_warn(&dev->dev,
|
dev_warn(&dev->dev,
|
||||||
"This server does not have an iLO2 ASIC.\n");
|
"This server does not have an iLO2 ASIC.\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,7 +672,7 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev,
|
||||||
retval = detect_cru_service();
|
retval = detect_cru_service();
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
dev_warn(&dev->dev,
|
dev_warn(&dev->dev,
|
||||||
"Unable to detect the %d Bit CRU Service.\n",
|
"Unable to detect the %d Bit CRU Service.\n",
|
||||||
HPWDT_ARCH);
|
HPWDT_ARCH);
|
||||||
goto error_get_cru;
|
goto error_get_cru;
|
||||||
}
|
}
|
||||||
|
@ -684,7 +687,7 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev,
|
||||||
retval = register_die_notifier(&die_notifier);
|
retval = register_die_notifier(&die_notifier);
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
dev_warn(&dev->dev,
|
dev_warn(&dev->dev,
|
||||||
"Unable to register a die notifier (err=%d).\n",
|
"Unable to register a die notifier (err=%d).\n",
|
||||||
retval);
|
retval);
|
||||||
goto error_die_notifier;
|
goto error_die_notifier;
|
||||||
}
|
}
|
||||||
|
@ -699,8 +702,9 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev,
|
||||||
|
|
||||||
printk(KERN_INFO
|
printk(KERN_INFO
|
||||||
"hp Watchdog Timer Driver: 1.00"
|
"hp Watchdog Timer Driver: 1.00"
|
||||||
", timer margin: %d seconds( nowayout=%d).\n",
|
", timer margin: %d seconds (nowayout=%d)"
|
||||||
soft_margin, nowayout);
|
", allow kernel dump: %s (default = 0/OFF).\n",
|
||||||
|
soft_margin, nowayout, (allow_kdump == 0) ? "OFF" : "ON");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -755,6 +759,9 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
|
||||||
module_param(soft_margin, int, 0);
|
module_param(soft_margin, int, 0);
|
||||||
MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
|
MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
|
||||||
|
|
||||||
|
module_param(allow_kdump, int, 0);
|
||||||
|
MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs");
|
||||||
|
|
||||||
module_param(nowayout, int, 0);
|
module_param(nowayout, int, 0);
|
||||||
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
|
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
|
||||||
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||||
|
|
|
@ -1,170 +0,0 @@
|
||||||
/*
|
|
||||||
* mpc8xx_wdt.c - MPC8xx watchdog userspace interface
|
|
||||||
*
|
|
||||||
* Author: Florian Schirmer <jolt@tuxbox.org>
|
|
||||||
*
|
|
||||||
* 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
|
|
||||||
* the terms of the GNU General Public License version 2. This program
|
|
||||||
* is licensed "as is" without any warranty of any kind, whether express
|
|
||||||
* or implied.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/miscdevice.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/watchdog.h>
|
|
||||||
#include <asm/8xx_immap.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <syslib/m8xx_wdt.h>
|
|
||||||
|
|
||||||
static unsigned long wdt_opened;
|
|
||||||
static int wdt_status;
|
|
||||||
static spinlock_t wdt_lock;
|
|
||||||
|
|
||||||
static void mpc8xx_wdt_handler_disable(void)
|
|
||||||
{
|
|
||||||
volatile uint __iomem *piscr;
|
|
||||||
piscr = (uint *)&((immap_t *)IMAP_ADDR)->im_sit.sit_piscr;
|
|
||||||
|
|
||||||
if (!m8xx_has_internal_rtc)
|
|
||||||
m8xx_wdt_stop_timer();
|
|
||||||
else
|
|
||||||
out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE));
|
|
||||||
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mpc8xx_wdt_handler_enable(void)
|
|
||||||
{
|
|
||||||
volatile uint __iomem *piscr;
|
|
||||||
piscr = (uint *)&((immap_t *)IMAP_ADDR)->im_sit.sit_piscr;
|
|
||||||
|
|
||||||
if (!m8xx_has_internal_rtc)
|
|
||||||
m8xx_wdt_install_timer();
|
|
||||||
else
|
|
||||||
out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE);
|
|
||||||
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
if (test_and_set_bit(0, &wdt_opened))
|
|
||||||
return -EBUSY;
|
|
||||||
m8xx_wdt_reset();
|
|
||||||
mpc8xx_wdt_handler_disable();
|
|
||||||
return nonseekable_open(inode, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
m8xx_wdt_reset();
|
|
||||||
#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
|
|
||||||
mpc8xx_wdt_handler_enable();
|
|
||||||
#endif
|
|
||||||
clear_bit(0, &wdt_opened);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t mpc8xx_wdt_write(struct file *file, const char *data,
|
|
||||||
size_t len, loff_t *ppos)
|
|
||||||
{
|
|
||||||
if (len) {
|
|
||||||
spin_lock(&wdt_lock);
|
|
||||||
m8xx_wdt_reset();
|
|
||||||
spin_unlock(&wdt_lock);
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long mpc8xx_wdt_ioctl(struct file *file,
|
|
||||||
unsigned int cmd, unsigned long arg)
|
|
||||||
{
|
|
||||||
int timeout;
|
|
||||||
static struct watchdog_info info = {
|
|
||||||
.options = WDIOF_KEEPALIVEPING,
|
|
||||||
.firmware_version = 0,
|
|
||||||
.identity = "MPC8xx watchdog",
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case WDIOC_GETSUPPORT:
|
|
||||||
if (copy_to_user((void *)arg, &info, sizeof(info)))
|
|
||||||
return -EFAULT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WDIOC_GETSTATUS:
|
|
||||||
case WDIOC_GETBOOTSTATUS:
|
|
||||||
if (put_user(wdt_status, (int *)arg))
|
|
||||||
return -EFAULT;
|
|
||||||
wdt_status &= ~WDIOF_KEEPALIVEPING;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WDIOC_GETTEMP:
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
case WDIOC_SETOPTIONS:
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
case WDIOC_KEEPALIVE:
|
|
||||||
spin_lock(&wdt_lock);
|
|
||||||
m8xx_wdt_reset();
|
|
||||||
wdt_status |= WDIOF_KEEPALIVEPING;
|
|
||||||
spin_unlock(&wdt_lock);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WDIOC_SETTIMEOUT:
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
case WDIOC_GETTIMEOUT:
|
|
||||||
spin_lock(&wdt_lock);
|
|
||||||
timeout = m8xx_wdt_get_timeout();
|
|
||||||
spin_unlock(&wdt_lock);
|
|
||||||
if (put_user(timeout, (int *)arg))
|
|
||||||
return -EFAULT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return -ENOTTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct file_operations mpc8xx_wdt_fops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.llseek = no_llseek,
|
|
||||||
.write = mpc8xx_wdt_write,
|
|
||||||
.unlocked_ioctl = mpc8xx_wdt_ioctl,
|
|
||||||
.open = mpc8xx_wdt_open,
|
|
||||||
.release = mpc8xx_wdt_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct miscdevice mpc8xx_wdt_miscdev = {
|
|
||||||
.minor = WATCHDOG_MINOR,
|
|
||||||
.name = "watchdog",
|
|
||||||
.fops = &mpc8xx_wdt_fops,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init mpc8xx_wdt_init(void)
|
|
||||||
{
|
|
||||||
spin_lock_init(&wdt_lock);
|
|
||||||
return misc_register(&mpc8xx_wdt_miscdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit mpc8xx_wdt_exit(void)
|
|
||||||
{
|
|
||||||
misc_deregister(&mpc8xx_wdt_miscdev);
|
|
||||||
|
|
||||||
m8xx_wdt_reset();
|
|
||||||
mpc8xx_wdt_handler_enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(mpc8xx_wdt_init);
|
|
||||||
module_exit(mpc8xx_wdt_exit);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
|
|
||||||
MODULE_DESCRIPTION("MPC8xx watchdog driver");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
|
|
|
@ -48,6 +48,7 @@ struct mpc8xxx_wdt_type {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mpc8xxx_wdt __iomem *wd_base;
|
static struct mpc8xxx_wdt __iomem *wd_base;
|
||||||
|
static int mpc8xxx_wdt_init_late(void);
|
||||||
|
|
||||||
static u16 timeout = 0xffff;
|
static u16 timeout = 0xffff;
|
||||||
module_param(timeout, ushort, 0);
|
module_param(timeout, ushort, 0);
|
||||||
|
@ -213,6 +214,12 @@ static int __devinit mpc8xxx_wdt_probe(struct of_device *ofdev,
|
||||||
else
|
else
|
||||||
timeout_sec = timeout / freq;
|
timeout_sec = timeout / freq;
|
||||||
|
|
||||||
|
#ifdef MODULE
|
||||||
|
ret = mpc8xxx_wdt_init_late();
|
||||||
|
if (ret)
|
||||||
|
goto err_unmap;
|
||||||
|
#endif
|
||||||
|
|
||||||
pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d "
|
pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d "
|
||||||
"(%d seconds)\n", reset ? "reset" : "interrupt", timeout,
|
"(%d seconds)\n", reset ? "reset" : "interrupt", timeout,
|
||||||
timeout_sec);
|
timeout_sec);
|
||||||
|
@ -280,7 +287,7 @@ static struct of_platform_driver mpc8xxx_wdt_driver = {
|
||||||
* very early to start pinging the watchdog (misc devices are not yet
|
* very early to start pinging the watchdog (misc devices are not yet
|
||||||
* available), and later module_init() just registers the misc device.
|
* available), and later module_init() just registers the misc device.
|
||||||
*/
|
*/
|
||||||
static int __init mpc8xxx_wdt_init_late(void)
|
static int mpc8xxx_wdt_init_late(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -295,7 +302,9 @@ static int __init mpc8xxx_wdt_init_late(void)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#ifndef MODULE
|
||||||
module_init(mpc8xxx_wdt_init_late);
|
module_init(mpc8xxx_wdt_init_late);
|
||||||
|
#endif
|
||||||
|
|
||||||
static int __init mpc8xxx_wdt_init(void)
|
static int __init mpc8xxx_wdt_init(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,344 @@
|
||||||
|
/*
|
||||||
|
* IDT Interprise 79RC32434 watchdog driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006, Ondrej Zajicek <santiago@crfreenet.org>
|
||||||
|
* Copyright (C) 2008, Florian Fainelli <florian@openwrt.org>
|
||||||
|
*
|
||||||
|
* based on
|
||||||
|
* SoftDog 0.05: A Software Watchdog Device
|
||||||
|
*
|
||||||
|
* (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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; either version
|
||||||
|
* 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/watchdog.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
|
#include <linux/smp_lock.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
#include <asm/bootinfo.h>
|
||||||
|
#include <asm/time.h>
|
||||||
|
#include <asm/mach-rc32434/integ.h>
|
||||||
|
|
||||||
|
#define MAX_TIMEOUT 20
|
||||||
|
#define RC32434_WDT_INTERVAL (15 * HZ)
|
||||||
|
|
||||||
|
#define VERSION "0.2"
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct completion stop;
|
||||||
|
int running;
|
||||||
|
struct timer_list timer;
|
||||||
|
int queue;
|
||||||
|
int default_ticks;
|
||||||
|
unsigned long inuse;
|
||||||
|
} rc32434_wdt_device;
|
||||||
|
|
||||||
|
static struct integ __iomem *wdt_reg;
|
||||||
|
static int ticks = 100 * HZ;
|
||||||
|
|
||||||
|
static int expect_close;
|
||||||
|
static int timeout;
|
||||||
|
|
||||||
|
static int nowayout = WATCHDOG_NOWAYOUT;
|
||||||
|
module_param(nowayout, int, 0);
|
||||||
|
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
|
||||||
|
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||||
|
|
||||||
|
|
||||||
|
static void rc32434_wdt_start(void)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (!rc32434_wdt_device.inuse) {
|
||||||
|
writel(0, &wdt_reg->wtcount);
|
||||||
|
|
||||||
|
val = RC32434_ERR_WRE;
|
||||||
|
writel(readl(&wdt_reg->errcs) | val, &wdt_reg->errcs);
|
||||||
|
|
||||||
|
val = RC32434_WTC_EN;
|
||||||
|
writel(readl(&wdt_reg->wtc) | val, &wdt_reg->wtc);
|
||||||
|
}
|
||||||
|
rc32434_wdt_device.running++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rc32434_wdt_stop(void)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (rc32434_wdt_device.running) {
|
||||||
|
|
||||||
|
val = ~RC32434_WTC_EN;
|
||||||
|
writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc);
|
||||||
|
|
||||||
|
val = ~RC32434_ERR_WRE;
|
||||||
|
writel(readl(&wdt_reg->errcs) & val, &wdt_reg->errcs);
|
||||||
|
|
||||||
|
rc32434_wdt_device.running = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rc32434_wdt_set(int new_timeout)
|
||||||
|
{
|
||||||
|
u32 cmp = new_timeout * HZ;
|
||||||
|
u32 state, val;
|
||||||
|
|
||||||
|
timeout = new_timeout;
|
||||||
|
/*
|
||||||
|
* store and disable WTC
|
||||||
|
*/
|
||||||
|
state = (u32)(readl(&wdt_reg->wtc) & RC32434_WTC_EN);
|
||||||
|
val = ~RC32434_WTC_EN;
|
||||||
|
writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc);
|
||||||
|
|
||||||
|
writel(0, &wdt_reg->wtcount);
|
||||||
|
writel(cmp, &wdt_reg->wtcompare);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* restore WTC
|
||||||
|
*/
|
||||||
|
|
||||||
|
writel(readl(&wdt_reg->wtc) | state, &wdt_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rc32434_wdt_reset(void)
|
||||||
|
{
|
||||||
|
ticks = rc32434_wdt_device.default_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rc32434_wdt_update(unsigned long unused)
|
||||||
|
{
|
||||||
|
if (rc32434_wdt_device.running)
|
||||||
|
ticks--;
|
||||||
|
|
||||||
|
writel(0, &wdt_reg->wtcount);
|
||||||
|
|
||||||
|
if (rc32434_wdt_device.queue && ticks)
|
||||||
|
mod_timer(&rc32434_wdt_device.timer,
|
||||||
|
jiffies + RC32434_WDT_INTERVAL);
|
||||||
|
else
|
||||||
|
complete(&rc32434_wdt_device.stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc32434_wdt_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
if (test_and_set_bit(0, &rc32434_wdt_device.inuse))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (nowayout)
|
||||||
|
__module_get(THIS_MODULE);
|
||||||
|
|
||||||
|
return nonseekable_open(inode, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc32434_wdt_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
if (expect_close && nowayout == 0) {
|
||||||
|
rc32434_wdt_stop();
|
||||||
|
printk(KERN_INFO KBUILD_MODNAME ": disabling watchdog timer\n");
|
||||||
|
module_put(THIS_MODULE);
|
||||||
|
} else
|
||||||
|
printk(KERN_CRIT KBUILD_MODNAME
|
||||||
|
": device closed unexpectedly. WDT will not stop !\n");
|
||||||
|
|
||||||
|
clear_bit(0, &rc32434_wdt_device.inuse);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t rc32434_wdt_write(struct file *file, const char *data,
|
||||||
|
size_t len, loff_t *ppos)
|
||||||
|
{
|
||||||
|
if (len) {
|
||||||
|
if (!nowayout) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* In case it was set long ago */
|
||||||
|
expect_close = 0;
|
||||||
|
|
||||||
|
for (i = 0; i != len; i++) {
|
||||||
|
char c;
|
||||||
|
if (get_user(c, data + i))
|
||||||
|
return -EFAULT;
|
||||||
|
if (c == 'V')
|
||||||
|
expect_close = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc32434_wdt_update(0);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc32434_wdt_ioctl(struct inode *inode, struct file *file,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
int new_timeout;
|
||||||
|
unsigned int value;
|
||||||
|
static struct watchdog_info ident = {
|
||||||
|
.options = WDIOF_SETTIMEOUT |
|
||||||
|
WDIOF_KEEPALIVEPING |
|
||||||
|
WDIOF_MAGICCLOSE,
|
||||||
|
.identity = "RC32434_WDT Watchdog",
|
||||||
|
};
|
||||||
|
switch (cmd) {
|
||||||
|
case WDIOC_KEEPALIVE:
|
||||||
|
rc32434_wdt_reset();
|
||||||
|
break;
|
||||||
|
case WDIOC_GETSTATUS:
|
||||||
|
case WDIOC_GETBOOTSTATUS:
|
||||||
|
value = readl(&wdt_reg->wtcount);
|
||||||
|
if (copy_to_user(argp, &value, sizeof(int)))
|
||||||
|
return -EFAULT;
|
||||||
|
break;
|
||||||
|
case WDIOC_GETSUPPORT:
|
||||||
|
if (copy_to_user(argp, &ident, sizeof(ident)))
|
||||||
|
return -EFAULT;
|
||||||
|
break;
|
||||||
|
case WDIOC_SETOPTIONS:
|
||||||
|
if (copy_from_user(&value, argp, sizeof(int)))
|
||||||
|
return -EFAULT;
|
||||||
|
switch (value) {
|
||||||
|
case WDIOS_ENABLECARD:
|
||||||
|
rc32434_wdt_start();
|
||||||
|
break;
|
||||||
|
case WDIOS_DISABLECARD:
|
||||||
|
rc32434_wdt_stop();
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WDIOC_SETTIMEOUT:
|
||||||
|
if (copy_from_user(&new_timeout, argp, sizeof(int)))
|
||||||
|
return -EFAULT;
|
||||||
|
if (new_timeout < 1)
|
||||||
|
return -EINVAL;
|
||||||
|
if (new_timeout > MAX_TIMEOUT)
|
||||||
|
return -EINVAL;
|
||||||
|
rc32434_wdt_set(new_timeout);
|
||||||
|
case WDIOC_GETTIMEOUT:
|
||||||
|
return copy_to_user(argp, &timeout, sizeof(int));
|
||||||
|
default:
|
||||||
|
return -ENOTTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_operations rc32434_wdt_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.llseek = no_llseek,
|
||||||
|
.write = rc32434_wdt_write,
|
||||||
|
.ioctl = rc32434_wdt_ioctl,
|
||||||
|
.open = rc32434_wdt_open,
|
||||||
|
.release = rc32434_wdt_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct miscdevice rc32434_wdt_miscdev = {
|
||||||
|
.minor = WATCHDOG_MINOR,
|
||||||
|
.name = "watchdog",
|
||||||
|
.fops = &rc32434_wdt_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char banner[] = KERN_INFO KBUILD_MODNAME
|
||||||
|
": Watchdog Timer version " VERSION ", timer margin: %d sec\n";
|
||||||
|
|
||||||
|
static int rc32434_wdt_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct resource *r;
|
||||||
|
|
||||||
|
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb500_wdt_res");
|
||||||
|
if (!r) {
|
||||||
|
printk(KERN_ERR KBUILD_MODNAME
|
||||||
|
"failed to retrieve resources\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdt_reg = ioremap_nocache(r->start, r->end - r->start);
|
||||||
|
if (!wdt_reg) {
|
||||||
|
printk(KERN_ERR KBUILD_MODNAME
|
||||||
|
"failed to remap I/O resources\n");
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = misc_register(&rc32434_wdt_miscdev);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
printk(KERN_ERR KBUILD_MODNAME
|
||||||
|
"failed to register watchdog device\n");
|
||||||
|
goto unmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_completion(&rc32434_wdt_device.stop);
|
||||||
|
rc32434_wdt_device.queue = 0;
|
||||||
|
|
||||||
|
clear_bit(0, &rc32434_wdt_device.inuse);
|
||||||
|
|
||||||
|
setup_timer(&rc32434_wdt_device.timer, rc32434_wdt_update, 0L);
|
||||||
|
|
||||||
|
rc32434_wdt_device.default_ticks = ticks;
|
||||||
|
|
||||||
|
rc32434_wdt_start();
|
||||||
|
|
||||||
|
printk(banner, timeout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unmap:
|
||||||
|
iounmap(wdt_reg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc32434_wdt_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
if (rc32434_wdt_device.queue) {
|
||||||
|
rc32434_wdt_device.queue = 0;
|
||||||
|
wait_for_completion(&rc32434_wdt_device.stop);
|
||||||
|
}
|
||||||
|
misc_deregister(&rc32434_wdt_miscdev);
|
||||||
|
|
||||||
|
iounmap(wdt_reg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver rc32434_wdt = {
|
||||||
|
.probe = rc32434_wdt_probe,
|
||||||
|
.remove = rc32434_wdt_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "rc32434_wdt",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rc32434_wdt_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&rc32434_wdt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit rc32434_wdt_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&rc32434_wdt);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(rc32434_wdt_init);
|
||||||
|
module_exit(rc32434_wdt_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Ondrej Zajicek <santiago@crfreenet.org>,"
|
||||||
|
"Florian Fainelli <florian@openwrt.org>");
|
||||||
|
MODULE_DESCRIPTION("Driver for the IDT RC32434 SoC watchdog");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
|
|
@ -0,0 +1,285 @@
|
||||||
|
/*
|
||||||
|
* RDC321x watchdog driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
|
||||||
|
*
|
||||||
|
* This driver is highly inspired from the cpu5_wdt driver
|
||||||
|
*
|
||||||
|
* 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/watchdog.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
#include <asm/mach-rdc321x/rdc321x_defs.h>
|
||||||
|
|
||||||
|
#define RDC_WDT_MASK 0x80000000 /* Mask */
|
||||||
|
#define RDC_WDT_EN 0x00800000 /* Enable bit */
|
||||||
|
#define RDC_WDT_WTI 0x00200000 /* Generate CPU reset/NMI/WDT on timeout */
|
||||||
|
#define RDC_WDT_RST 0x00100000 /* Reset bit */
|
||||||
|
#define RDC_WDT_WIF 0x00040000 /* WDT IRQ Flag */
|
||||||
|
#define RDC_WDT_IRT 0x00000100 /* IRQ Routing table */
|
||||||
|
#define RDC_WDT_CNT 0x00000001 /* WDT count */
|
||||||
|
|
||||||
|
#define RDC_CLS_TMR 0x80003844 /* Clear timer */
|
||||||
|
|
||||||
|
#define RDC_WDT_INTERVAL (HZ/10+1)
|
||||||
|
|
||||||
|
static int ticks = 1000;
|
||||||
|
|
||||||
|
/* some device data */
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct completion stop;
|
||||||
|
int running;
|
||||||
|
struct timer_list timer;
|
||||||
|
int queue;
|
||||||
|
int default_ticks;
|
||||||
|
unsigned long inuse;
|
||||||
|
spinlock_t lock;
|
||||||
|
} rdc321x_wdt_device;
|
||||||
|
|
||||||
|
/* generic helper functions */
|
||||||
|
|
||||||
|
static void rdc321x_wdt_trigger(unsigned long unused)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (rdc321x_wdt_device.running)
|
||||||
|
ticks--;
|
||||||
|
|
||||||
|
/* keep watchdog alive */
|
||||||
|
spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
|
||||||
|
outl(RDC_WDT_EN | inl(RDC3210_CFGREG_DATA),
|
||||||
|
RDC3210_CFGREG_DATA);
|
||||||
|
spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
|
||||||
|
|
||||||
|
/* requeue?? */
|
||||||
|
if (rdc321x_wdt_device.queue && ticks)
|
||||||
|
mod_timer(&rdc321x_wdt_device.timer,
|
||||||
|
jiffies + RDC_WDT_INTERVAL);
|
||||||
|
else {
|
||||||
|
/* ticks doesn't matter anyway */
|
||||||
|
complete(&rdc321x_wdt_device.stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rdc321x_wdt_reset(void)
|
||||||
|
{
|
||||||
|
ticks = rdc321x_wdt_device.default_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rdc321x_wdt_start(void)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (!rdc321x_wdt_device.queue) {
|
||||||
|
rdc321x_wdt_device.queue = 1;
|
||||||
|
|
||||||
|
/* Clear the timer */
|
||||||
|
spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
|
||||||
|
outl(RDC_CLS_TMR, RDC3210_CFGREG_ADDR);
|
||||||
|
|
||||||
|
/* Enable watchdog and set the timeout to 81.92 us */
|
||||||
|
outl(RDC_WDT_EN | RDC_WDT_CNT, RDC3210_CFGREG_DATA);
|
||||||
|
spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
|
||||||
|
|
||||||
|
mod_timer(&rdc321x_wdt_device.timer,
|
||||||
|
jiffies + RDC_WDT_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if process dies, counter is not decremented */
|
||||||
|
rdc321x_wdt_device.running++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rdc321x_wdt_stop(void)
|
||||||
|
{
|
||||||
|
if (rdc321x_wdt_device.running)
|
||||||
|
rdc321x_wdt_device.running = 0;
|
||||||
|
|
||||||
|
ticks = rdc321x_wdt_device.default_ticks;
|
||||||
|
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* filesystem operations */
|
||||||
|
static int rdc321x_wdt_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
if (test_and_set_bit(0, &rdc321x_wdt_device.inuse))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
return nonseekable_open(inode, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rdc321x_wdt_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
clear_bit(0, &rdc321x_wdt_device.inuse);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rdc321x_wdt_ioctl(struct inode *inode, struct file *file,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
unsigned int value;
|
||||||
|
static struct watchdog_info ident = {
|
||||||
|
.options = WDIOF_CARDRESET,
|
||||||
|
.identity = "RDC321x WDT",
|
||||||
|
};
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case WDIOC_KEEPALIVE:
|
||||||
|
rdc321x_wdt_reset();
|
||||||
|
break;
|
||||||
|
case WDIOC_GETSTATUS:
|
||||||
|
/* Read the value from the DATA register */
|
||||||
|
spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
|
||||||
|
value = inl(RDC3210_CFGREG_DATA);
|
||||||
|
spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
|
||||||
|
if (copy_to_user(argp, &value, sizeof(int)))
|
||||||
|
return -EFAULT;
|
||||||
|
break;
|
||||||
|
case WDIOC_GETSUPPORT:
|
||||||
|
if (copy_to_user(argp, &ident, sizeof(ident)))
|
||||||
|
return -EFAULT;
|
||||||
|
break;
|
||||||
|
case WDIOC_SETOPTIONS:
|
||||||
|
if (copy_from_user(&value, argp, sizeof(int)))
|
||||||
|
return -EFAULT;
|
||||||
|
switch (value) {
|
||||||
|
case WDIOS_ENABLECARD:
|
||||||
|
rdc321x_wdt_start();
|
||||||
|
break;
|
||||||
|
case WDIOS_DISABLECARD:
|
||||||
|
return rdc321x_wdt_stop();
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTTY;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t rdc321x_wdt_write(struct file *file, const char __user *buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
if (!count)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
rdc321x_wdt_reset();
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations rdc321x_wdt_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.llseek = no_llseek,
|
||||||
|
.ioctl = rdc321x_wdt_ioctl,
|
||||||
|
.open = rdc321x_wdt_open,
|
||||||
|
.write = rdc321x_wdt_write,
|
||||||
|
.release = rdc321x_wdt_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct miscdevice rdc321x_wdt_misc = {
|
||||||
|
.minor = WATCHDOG_MINOR,
|
||||||
|
.name = "watchdog",
|
||||||
|
.fops = &rdc321x_wdt_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = misc_register(&rdc321x_wdt_misc);
|
||||||
|
if (err < 0) {
|
||||||
|
printk(KERN_ERR PFX "watchdog misc_register failed\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&rdc321x_wdt_device.lock);
|
||||||
|
|
||||||
|
/* Reset the watchdog */
|
||||||
|
outl(RDC_WDT_RST, RDC3210_CFGREG_DATA);
|
||||||
|
|
||||||
|
init_completion(&rdc321x_wdt_device.stop);
|
||||||
|
rdc321x_wdt_device.queue = 0;
|
||||||
|
|
||||||
|
clear_bit(0, &rdc321x_wdt_device.inuse);
|
||||||
|
|
||||||
|
setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_trigger, 0);
|
||||||
|
|
||||||
|
rdc321x_wdt_device.default_ticks = ticks;
|
||||||
|
|
||||||
|
printk(KERN_INFO PFX "watchdog init success\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rdc321x_wdt_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
if (rdc321x_wdt_device.queue) {
|
||||||
|
rdc321x_wdt_device.queue = 0;
|
||||||
|
wait_for_completion(&rdc321x_wdt_device.stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
misc_deregister(&rdc321x_wdt_misc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver rdc321x_wdt_driver = {
|
||||||
|
.probe = rdc321x_wdt_probe,
|
||||||
|
.remove = rdc321x_wdt_remove,
|
||||||
|
.driver = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.name = "rdc321x-wdt",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rdc321x_wdt_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&rdc321x_wdt_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit rdc321x_wdt_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&rdc321x_wdt_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(rdc321x_wdt_init);
|
||||||
|
module_exit(rdc321x_wdt_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
|
||||||
|
MODULE_DESCRIPTION("RDC321x watchdog driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
|
|
@ -21,18 +21,6 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
|
||||||
* Changelog:
|
|
||||||
* 05-Oct-2004 BJD Added semaphore init to stop crashes on open
|
|
||||||
* Fixed tmr_count / wdt_count confusion
|
|
||||||
* Added configurable debug
|
|
||||||
*
|
|
||||||
* 11-Jan-2005 BJD Fixed divide-by-2 in timeout code
|
|
||||||
*
|
|
||||||
* 25-Jan-2005 DA Added suspend/resume support
|
|
||||||
* Replaced reboot notifier with .shutdown method
|
|
||||||
*
|
|
||||||
* 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -365,7 +353,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = (res->end-res->start)+1;
|
size = (res->end - res->start) + 1;
|
||||||
wdt_mem = request_mem_region(res->start, size, pdev->name);
|
wdt_mem = request_mem_region(res->start, size, pdev->name);
|
||||||
if (wdt_mem == NULL) {
|
if (wdt_mem == NULL) {
|
||||||
dev_err(dev, "failed to get memory region\n");
|
dev_err(dev, "failed to get memory region\n");
|
||||||
|
@ -374,7 +362,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
wdt_base = ioremap(res->start, size);
|
wdt_base = ioremap(res->start, size);
|
||||||
if (wdt_base == 0) {
|
if (wdt_base == NULL) {
|
||||||
dev_err(dev, "failed to ioremap() region\n");
|
dev_err(dev, "failed to ioremap() region\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err_req;
|
goto err_req;
|
||||||
|
|
Loading…
Reference in New Issue