Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
a8cd2e50
Commit
a8cd2e50
authored
Sep 13, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
parents
0160f53e
c315b7e8
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
2252 additions
and
43 deletions
+2252
-43
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Kconfig
+72
-21
drivers/char/watchdog/Makefile
drivers/char/watchdog/Makefile
+6
-1
drivers/char/watchdog/i6300esb.c
drivers/char/watchdog/i6300esb.c
+527
-0
drivers/char/watchdog/ibmasr.c
drivers/char/watchdog/ibmasr.c
+405
-0
drivers/char/watchdog/mv64x60_wdt.c
drivers/char/watchdog/mv64x60_wdt.c
+252
-0
drivers/char/watchdog/pcwd_pci.c
drivers/char/watchdog/pcwd_pci.c
+24
-20
drivers/char/watchdog/s3c2410_wdt.c
drivers/char/watchdog/s3c2410_wdt.c
+1
-1
drivers/char/watchdog/sbc8360.c
drivers/char/watchdog/sbc8360.c
+414
-0
drivers/char/watchdog/w83977f_wdt.c
drivers/char/watchdog/w83977f_wdt.c
+543
-0
include/asm-ppc/mv64x60.h
include/asm-ppc/mv64x60.h
+8
-0
No files found.
drivers/char/watchdog/Kconfig
View file @
a8cd2e50
...
@@ -84,6 +84,17 @@ config 977_WATCHDOG
...
@@ -84,6 +84,17 @@ config 977_WATCHDOG
Not sure? It's safe to say N.
Not sure? It's safe to say N.
config IXP2000_WATCHDOG
tristate "IXP2000 Watchdog"
depends on WATCHDOG && ARCH_IXP2000
help
Say Y here if to include support for the watchdog timer
in the Intel IXP2000(2400, 2800, 2850) network processors.
This driver can be built as a module by choosing M. The module
will be called ixp2000_wdt.
Say N if you are unsure.
config IXP4XX_WATCHDOG
config IXP4XX_WATCHDOG
tristate "IXP4xx Watchdog"
tristate "IXP4xx Watchdog"
depends on WATCHDOG && ARCH_IXP4XX
depends on WATCHDOG && ARCH_IXP4XX
...
@@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG
...
@@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG
Say N if you are unsure.
Say N if you are unsure.
config IXP2000_WATCHDOG
tristate "IXP2000 Watchdog"
depends on WATCHDOG && ARCH_IXP2000
help
Say Y here if to include support for the watchdog timer
in the Intel IXP2000(2400, 2800, 2850) network processors.
This driver can be built as a module by choosing M. The module
will be called ixp2000_wdt.
Say N if you are unsure.
config S3C2410_WATCHDOG
config S3C2410_WATCHDOG
tristate "S3C2410 Watchdog"
tristate "S3C2410 Watchdog"
depends on WATCHDOG && ARCH_S3C2410
depends on WATCHDOG && ARCH_S3C2410
...
@@ -233,6 +233,16 @@ config IB700_WDT
...
@@ -233,6 +233,16 @@ config IB700_WDT
Most people will say N.
Most people will say N.
config IBMASR
tristate "IBM Automatic Server Restart"
depends on WATCHDOG && X86
help
This is the driver for the IBM Automatic Server Restart watchdog
timer builtin into some eServer xSeries machines.
To compile this driver as a module, choose M here: the
module will be called ibmasr.
config WAFER_WDT
config WAFER_WDT
tristate "ICP Wafer 5823 Single Board Computer Watchdog"
tristate "ICP Wafer 5823 Single Board Computer Watchdog"
depends on WATCHDOG && X86
depends on WATCHDOG && X86
...
@@ -243,6 +253,16 @@ config WAFER_WDT
...
@@ -243,6 +253,16 @@ config WAFER_WDT
To compile this driver as a module, choose M here: the
To compile this driver as a module, choose M here: the
module will be called wafer5823wdt.
module will be called wafer5823wdt.
config I6300ESB_WDT
tristate "Intel 6300ESB Timer/Watchdog"
depends on WATCHDOG && X86 && PCI
---help---
Hardware driver for the watchdog timer built into the Intel
6300ESB controller hub.
To compile this driver as a module, choose M here: the
module will be called i6300esb.
config I8XX_TCO
config I8XX_TCO
tristate "Intel i8xx TCO Timer/Watchdog"
tristate "Intel i8xx TCO Timer/Watchdog"
depends on WATCHDOG && (X86 || IA64) && PCI
depends on WATCHDOG && (X86 || IA64) && PCI
...
@@ -298,6 +318,19 @@ config 60XX_WDT
...
@@ -298,6 +318,19 @@ config 60XX_WDT
You can compile this driver directly into the kernel, or use
You can compile this driver directly into the kernel, or use
it as a module. The module will be called sbc60xxwdt.
it as a module. The module will be called sbc60xxwdt.
config SBC8360_WDT
tristate "SBC8360 Watchdog Timer"
depends on WATCHDOG && X86
---help---
This is the driver for the hardware watchdog on the SBC8360 Single
Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com).
To compile this driver as a module, choose M here: the
module will be called sbc8360.ko.
Most people will say N.
config CPU5_WDT
config CPU5_WDT
tristate "SMA CPU5 Watchdog"
tristate "SMA CPU5 Watchdog"
depends on WATCHDOG && X86
depends on WATCHDOG && X86
...
@@ -336,6 +369,19 @@ config W83877F_WDT
...
@@ -336,6 +369,19 @@ config W83877F_WDT
Most people will say N.
Most people will say N.
config W83977F_WDT
tristate "W83977F (PCM-5335) Watchdog Timer"
depends on WATCHDOG && X86
---help---
This is the driver for the hardware watchdog on the W83977F I/O chip
as used in AAEON's PCM-5335 SBC (and likely others). This
watchdog simply watches your kernel to make sure it doesn't freeze,
and if it does, it reboots your computer after a certain amount of
time.
To compile this driver as a module, choose M here: the
module will be called w83977f_wdt.
config MACHZ_WDT
config MACHZ_WDT
tristate "ZF MachZ Watchdog"
tristate "ZF MachZ Watchdog"
depends on WATCHDOG && X86
depends on WATCHDOG && X86
...
@@ -355,6 +401,10 @@ config 8xx_WDT
...
@@ -355,6 +401,10 @@ config 8xx_WDT
tristate "MPC8xx Watchdog Timer"
tristate "MPC8xx Watchdog Timer"
depends on WATCHDOG && 8xx
depends on WATCHDOG && 8xx
config MV64X60_WDT
tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
depends on WATCHDOG && MV64X60
config BOOKE_WDT
config BOOKE_WDT
tristate "PowerPC Book-E Watchdog Timer"
tristate "PowerPC Book-E Watchdog Timer"
depends on WATCHDOG && (BOOKE || 4xx)
depends on WATCHDOG && (BOOKE || 4xx)
...
@@ -362,6 +412,17 @@ config BOOKE_WDT
...
@@ -362,6 +412,17 @@ config BOOKE_WDT
Please see Documentation/watchdog/watchdog-api.txt for
Please see Documentation/watchdog/watchdog-api.txt for
more information.
more information.
# PPC64 Architecture
config WATCHDOG_RTAS
tristate "RTAS watchdog"
depends on WATCHDOG && PPC_RTAS
help
This driver adds watchdog support for the RTAS watchdog.
To compile this driver as a module, choose M here. The module
will be called wdrtas.
# MIPS Architecture
# MIPS Architecture
config INDYDOG
config INDYDOG
...
@@ -430,16 +491,6 @@ config WATCHDOG_RIO
...
@@ -430,16 +491,6 @@ config WATCHDOG_RIO
machines. The watchdog timeout period is normally one minute but
machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter.
can be changed with a boot-time parameter.
# ppc64 RTAS watchdog
config WATCHDOG_RTAS
tristate "RTAS watchdog"
depends on WATCHDOG && PPC_RTAS
help
This driver adds watchdog support for the RTAS watchdog.
To compile this driver as a module, choose M here. The module
will be called wdrtas.
#
#
# ISA-based Watchdog Cards
# ISA-based Watchdog Cards
#
#
...
...
drivers/char/watchdog/Makefile
View file @
a8cd2e50
...
@@ -39,22 +39,27 @@ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
...
@@ -39,22 +39,27 @@ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
obj-$(CONFIG_SC520_WDT)
+=
sc520_wdt.o
obj-$(CONFIG_SC520_WDT)
+=
sc520_wdt.o
obj-$(CONFIG_EUROTECH_WDT)
+=
eurotechwdt.o
obj-$(CONFIG_EUROTECH_WDT)
+=
eurotechwdt.o
obj-$(CONFIG_IB700_WDT)
+=
ib700wdt.o
obj-$(CONFIG_IB700_WDT)
+=
ib700wdt.o
obj-$(CONFIG_IBMASR)
+=
ibmasr.o
obj-$(CONFIG_WAFER_WDT)
+=
wafer5823wdt.o
obj-$(CONFIG_WAFER_WDT)
+=
wafer5823wdt.o
obj-$(CONFIG_I6300ESB_WDT)
+=
i6300esb.o
obj-$(CONFIG_I8XX_TCO)
+=
i8xx_tco.o
obj-$(CONFIG_I8XX_TCO)
+=
i8xx_tco.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_60XX_WDT)
+=
sbc60xxwdt.o
obj-$(CONFIG_60XX_WDT)
+=
sbc60xxwdt.o
obj-$(CONFIG_SBC8360_WDT)
+=
sbc8360.o
obj-$(CONFIG_CPU5_WDT)
+=
cpu5wdt.o
obj-$(CONFIG_CPU5_WDT)
+=
cpu5wdt.o
obj-$(CONFIG_W83627HF_WDT)
+=
w83627hf_wdt.o
obj-$(CONFIG_W83627HF_WDT)
+=
w83627hf_wdt.o
obj-$(CONFIG_W83877F_WDT)
+=
w83877f_wdt.o
obj-$(CONFIG_W83877F_WDT)
+=
w83877f_wdt.o
obj-$(CONFIG_W83977F_WDT)
+=
w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT)
+=
machzwd.o
obj-$(CONFIG_MACHZ_WDT)
+=
machzwd.o
# PowerPC Architecture
# PowerPC Architecture
obj-$(CONFIG_8xx_WDT)
+=
mpc8xx_wdt.o
obj-$(CONFIG_8xx_WDT)
+=
mpc8xx_wdt.o
obj-$(CONFIG_MV64X60_WDT)
+=
mv64x60_wdt.o
obj-$(CONFIG_BOOKE_WDT)
+=
booke_wdt.o
# PPC64 Architecture
# PPC64 Architecture
obj-$(CONFIG_WATCHDOG_RTAS)
+=
wdrtas.o
obj-$(CONFIG_WATCHDOG_RTAS)
+=
wdrtas.o
obj-$(CONFIG_BOOKE_WDT)
+=
booke_wdt.o
# MIPS Architecture
# MIPS Architecture
obj-$(CONFIG_INDYDOG)
+=
indydog.o
obj-$(CONFIG_INDYDOG)
+=
indydog.o
...
...
drivers/char/watchdog/i6300esb.c
0 → 100644
View file @
a8cd2e50
/*
* i6300esb: Watchdog timer driver for Intel 6300ESB chipset
*
* (c) Copyright 2004 Google Inc.
* (c) Copyright 2005 David Hrdeman <david@2gen.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* based on i810-tco.c which is in turn based on softdog.c
*
* The timer is implemented in the following I/O controller hubs:
* (See the intel documentation on http://developer.intel.com.)
* 6300ESB chip : document number 300641-003
*
* 2004YYZZ Ross Biro
* Initial version 0.01
* 2004YYZZ Ross Biro
* Version 0.02
* 20050210 David Hrdeman <david@2gen.com>
* Ported driver to kernel 2.6
*/
/*
* Includes, defines, variables, module parameters, ...
*/
#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/init.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/* Module and version information */
#define ESB_VERSION "0.03"
#define ESB_MODULE_NAME "i6300ESB timer"
#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
#define PFX ESB_MODULE_NAME ": "
/* PCI configuration registers */
#define ESB_CONFIG_REG 0x60
/* Config register */
#define ESB_LOCK_REG 0x68
/* WDT lock register */
/* Memory mapped registers */
#define ESB_TIMER1_REG BASEADDR + 0x00
/* Timer1 value after each reset */
#define ESB_TIMER2_REG BASEADDR + 0x04
/* Timer2 value after each reset */
#define ESB_GINTSR_REG BASEADDR + 0x08
/* General Interrupt Status Register */
#define ESB_RELOAD_REG BASEADDR + 0x0c
/* Reload register */
/* Lock register bits */
#define ESB_WDT_FUNC ( 0x01 << 2 )
/* Watchdog functionality */
#define ESB_WDT_ENABLE ( 0x01 << 1 )
/* Enable WDT */
#define ESB_WDT_LOCK ( 0x01 << 0 )
/* Lock (nowayout) */
/* Config register bits */
#define ESB_WDT_REBOOT ( 0x01 << 5 )
/* Enable reboot on timeout */
#define ESB_WDT_FREQ ( 0x01 << 2 )
/* Decrement frequency */
#define ESB_WDT_INTTYPE ( 0x11 << 0 )
/* Interrupt type on timer1 timeout */
/* Reload register bits */
#define ESB_WDT_RELOAD ( 0x01 << 8 )
/* prevent timeout */
/* Magic constants */
#define ESB_UNLOCK1 0x80
/* Step 1 to unlock reset registers */
#define ESB_UNLOCK2 0x86
/* Step 2 to unlock reset registers */
/* internal variables */
static
void
__iomem
*
BASEADDR
;
static
spinlock_t
esb_lock
;
/* Guards the hardware */
static
unsigned
long
timer_alive
;
static
struct
pci_dev
*
esb_pci
;
static
unsigned
short
triggered
;
/* The status of the watchdog upon boot */
static
char
esb_expect_close
;
/* module parameters */
#define WATCHDOG_HEARTBEAT 30
/* 30 sec default heartbeat (1<heartbeat<2*1023) */
static
int
heartbeat
=
WATCHDOG_HEARTBEAT
;
/* in seconds */
module_param
(
heartbeat
,
int
,
0
);
MODULE_PARM_DESC
(
heartbeat
,
"Watchdog heartbeat in seconds. (1<heartbeat<2046, default="
__MODULE_STRING
(
WATCHDOG_HEARTBEAT
)
")"
);
static
int
nowayout
=
WATCHDOG_NOWAYOUT
;
module_param
(
nowayout
,
int
,
0
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
/*
* Some i6300ESB specific functions
*/
/*
* Prepare for reloading the timer by unlocking the proper registers.
* This is performed by first writing 0x80 followed by 0x86 to the
* reload register. After this the appropriate registers can be written
* to once before they need to be unlocked again.
*/
static
inline
void
esb_unlock_registers
(
void
)
{
writeb
(
ESB_UNLOCK1
,
ESB_RELOAD_REG
);
writeb
(
ESB_UNLOCK2
,
ESB_RELOAD_REG
);
}
static
void
esb_timer_start
(
void
)
{
u8
val
;
/* Enable or Enable + Lock? */
val
=
0x02
|
(
nowayout
?
0x01
:
0x00
);
pci_write_config_byte
(
esb_pci
,
ESB_LOCK_REG
,
val
);
}
static
int
esb_timer_stop
(
void
)
{
u8
val
;
spin_lock
(
&
esb_lock
);
/* First, reset timers as suggested by the docs */
esb_unlock_registers
();
writew
(
ESB_WDT_RELOAD
,
ESB_RELOAD_REG
);
/* Then disable the WDT */
pci_write_config_byte
(
esb_pci
,
ESB_LOCK_REG
,
0x0
);
pci_read_config_byte
(
esb_pci
,
ESB_LOCK_REG
,
&
val
);
spin_unlock
(
&
esb_lock
);
/* Returns 0 if the timer was disabled, non-zero otherwise */
return
(
val
&
0x01
);
}
static
void
esb_timer_keepalive
(
void
)
{
spin_lock
(
&
esb_lock
);
esb_unlock_registers
();
writew
(
ESB_WDT_RELOAD
,
ESB_RELOAD_REG
);
/* FIXME: Do we need to flush anything here? */
spin_unlock
(
&
esb_lock
);
}
static
int
esb_timer_set_heartbeat
(
int
time
)
{
u32
val
;
if
(
time
<
0x1
||
time
>
(
2
*
0x03ff
))
return
-
EINVAL
;
spin_lock
(
&
esb_lock
);
/* We shift by 9, so if we are passed a value of 1 sec,
* val will be 1 << 9 = 512, then write that to two
* timers => 2 * 512 = 1024 (which is decremented at 1KHz)
*/
val
=
time
<<
9
;
/* Write timer 1 */
esb_unlock_registers
();
writel
(
val
,
ESB_TIMER1_REG
);
/* Write timer 2 */
esb_unlock_registers
();
writel
(
val
,
ESB_TIMER2_REG
);
/* Reload */
esb_unlock_registers
();
writew
(
ESB_WDT_RELOAD
,
ESB_RELOAD_REG
);
/* FIXME: Do we need to flush everything out? */
/* Done */
heartbeat
=
time
;
spin_unlock
(
&
esb_lock
);
return
0
;
}
static
int
esb_timer_read
(
void
)
{
u32
count
;
/* This isn't documented, and doesn't take into
* acount which stage is running, but it looks
* like a 20 bit count down, so we might as well report it.
*/
pci_read_config_dword
(
esb_pci
,
0x64
,
&
count
);
return
(
int
)
count
;
}
/*
* /dev/watchdog handling
*/
static
int
esb_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/* /dev/watchdog can only be opened once */
if
(
test_and_set_bit
(
0
,
&
timer_alive
))
return
-
EBUSY
;
/* Reload and activate timer */
esb_timer_keepalive
();
esb_timer_start
();
return
nonseekable_open
(
inode
,
file
);
}
static
int
esb_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/* Shut off the timer. */
if
(
esb_expect_close
==
42
)
{
esb_timer_stop
();
}
else
{
printk
(
KERN_CRIT
PFX
"Unexpected close, not stopping watchdog!
\n
"
);
esb_timer_keepalive
();
}
clear_bit
(
0
,
&
timer_alive
);
esb_expect_close
=
0
;
return
0
;
}
static
ssize_t
esb_write
(
struct
file
*
file
,
const
char
__user
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
/* See if we got the magic character 'V' and reload the timer */
if
(
len
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* note: just in case someone wrote the magic character
* five months ago... */
esb_expect_close
=
0
;
/* 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'
)
esb_expect_close
=
42
;
}
}
/* someone wrote to us, we should reload the timer */
esb_timer_keepalive
();
}
return
len
;
}
static
int
esb_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
new_options
,
retval
=
-
EINVAL
;
int
new_heartbeat
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
int
__user
*
p
=
argp
;
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
0
,
.
identity
=
ESB_MODULE_NAME
,
};
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
return
copy_to_user
(
argp
,
&
ident
,
sizeof
(
ident
))
?
-
EFAULT
:
0
;
case
WDIOC_GETSTATUS
:
return
put_user
(
esb_timer_read
(),
p
);
case
WDIOC_GETBOOTSTATUS
:
return
put_user
(
triggered
,
p
);
case
WDIOC_KEEPALIVE
:
esb_timer_keepalive
();
return
0
;
case
WDIOC_SETOPTIONS
:
{
if
(
get_user
(
new_options
,
p
))
return
-
EFAULT
;
if
(
new_options
&
WDIOS_DISABLECARD
)
{
esb_timer_stop
();
retval
=
0
;
}
if
(
new_options
&
WDIOS_ENABLECARD
)
{
esb_timer_keepalive
();
esb_timer_start
();
retval
=
0
;
}
return
retval
;
}
case
WDIOC_SETTIMEOUT
:
{
if
(
get_user
(
new_heartbeat
,
p
))
return
-
EFAULT
;
if
(
esb_timer_set_heartbeat
(
new_heartbeat
))
return
-
EINVAL
;
esb_timer_keepalive
();
/* Fall */
}
case
WDIOC_GETTIMEOUT
:
return
put_user
(
heartbeat
,
p
);
default:
return
-
ENOIOCTLCMD
;
}
}
/*
* Notify system
*/
static
int
esb_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
/* Turn the WDT off */
esb_timer_stop
();
}
return
NOTIFY_DONE
;
}
/*
* Kernel Interfaces
*/
static
struct
file_operations
esb_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
esb_write
,
.
ioctl
=
esb_ioctl
,
.
open
=
esb_open
,
.
release
=
esb_release
,
};
static
struct
miscdevice
esb_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
esb_fops
,
};
static
struct
notifier_block
esb_notifier
=
{
.
notifier_call
=
esb_notify_sys
,
};
/*
* Data for PCI driver interface
*
* This data only exists for exporting the supported
* PCI ids via MODULE_DEVICE_TABLE. We do not actually
* register a pci_driver, because someone else might one day
* want to register another driver on the same PCI id.
*/
static
struct
pci_device_id
esb_pci_tbl
[]
=
{
{
PCI_DEVICE
(
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_ESB_9
),
},
{
0
,
},
/* End of list */
};
MODULE_DEVICE_TABLE
(
pci
,
esb_pci_tbl
);
/*
* Init & exit routines
*/
static
unsigned
char
__init
esb_getdevice
(
void
)
{
u8
val1
;
unsigned
short
val2
;
struct
pci_dev
*
dev
=
NULL
;
/*
* Find the PCI device
*/
for_each_pci_dev
(
dev
)
{
if
(
pci_match_id
(
esb_pci_tbl
,
dev
))
{
esb_pci
=
dev
;
break
;
}
}
if
(
esb_pci
)
{
if
(
pci_enable_device
(
esb_pci
))
{
printk
(
KERN_ERR
PFX
"failed to enable device
\n
"
);
goto
err_devput
;
}
if
(
pci_request_region
(
esb_pci
,
0
,
ESB_MODULE_NAME
))
{
printk
(
KERN_ERR
PFX
"failed to request region
\n
"
);
goto
err_disable
;
}
BASEADDR
=
ioremap
(
pci_resource_start
(
esb_pci
,
0
),
pci_resource_len
(
esb_pci
,
0
));
if
(
BASEADDR
==
NULL
)
{
/* Something's wrong here, BASEADDR has to be set */
printk
(
KERN_ERR
PFX
"failed to get BASEADDR
\n
"
);
goto
err_release
;
}
/*
* The watchdog has two timers, it can be setup so that the
* expiry of timer1 results in an interrupt and the expiry of
* timer2 results in a reboot. We set it to not generate
* any interrupts as there is not much we can do with it
* right now.
*
* We also enable reboots and set the timer frequency to
* the PCI clock divided by 2^15 (approx 1KHz).
*/
pci_write_config_word
(
esb_pci
,
ESB_CONFIG_REG
,
0x0003
);
/* Check that the WDT isn't already locked */
pci_read_config_byte
(
esb_pci
,
ESB_LOCK_REG
,
&
val1
);
if
(
val1
&
ESB_WDT_LOCK
)
printk
(
KERN_WARNING
PFX
"nowayout already set
\n
"
);
/* Set the timer to watchdog mode and disable it for now */
pci_write_config_byte
(
esb_pci
,
ESB_LOCK_REG
,
0x00
);
/* Check if the watchdog was previously triggered */
esb_unlock_registers
();
val2
=
readw
(
ESB_RELOAD_REG
);
triggered
=
(
val2
&
(
0x01
<<
9
)
>>
9
);
/* Reset trigger flag and timers */
esb_unlock_registers
();
writew
((
0x11
<<
8
),
ESB_RELOAD_REG
);
/* Done */
return
1
;
err_release:
pci_release_region
(
esb_pci
,
0
);
err_disable:
pci_disable_device
(
esb_pci
);
err_devput:
pci_dev_put
(
esb_pci
);
}
return
0
;
}
static
int
__init
watchdog_init
(
void
)
{
int
ret
;
spin_lock_init
(
&
esb_lock
);
/* Check whether or not the hardware watchdog is there */
if
(
!
esb_getdevice
()
||
esb_pci
==
NULL
)
return
-
ENODEV
;
/* Check that the heartbeat value is within it's range ; if not reset to the default */
if
(
esb_timer_set_heartbeat
(
heartbeat
))
{
esb_timer_set_heartbeat
(
WATCHDOG_HEARTBEAT
);
printk
(
KERN_INFO
PFX
"heartbeat value must be 1<heartbeat<2046, using %d
\n
"
,
heartbeat
);
}
ret
=
register_reboot_notifier
(
&
esb_notifier
);
if
(
ret
!=
0
)
{
printk
(
KERN_ERR
PFX
"cannot register reboot notifier (err=%d)
\n
"
,
ret
);
goto
err_unmap
;
}
ret
=
misc_register
(
&
esb_miscdev
);
if
(
ret
!=
0
)
{
printk
(
KERN_ERR
PFX
"cannot register miscdev on minor=%d (err=%d)
\n
"
,
WATCHDOG_MINOR
,
ret
);
goto
err_notifier
;
}
esb_timer_stop
();
printk
(
KERN_INFO
PFX
"initialized (0x%p). heartbeat=%d sec (nowayout=%d)
\n
"
,
BASEADDR
,
heartbeat
,
nowayout
);
return
0
;
err_notifier:
unregister_reboot_notifier
(
&
esb_notifier
);
err_unmap:
iounmap
(
BASEADDR
);
/* err_release: */
pci_release_region
(
esb_pci
,
0
);
/* err_disable: */
pci_disable_device
(
esb_pci
);
/* err_devput: */
pci_dev_put
(
esb_pci
);
return
ret
;
}
static
void
__exit
watchdog_cleanup
(
void
)
{
/* Stop the timer before we leave */
if
(
!
nowayout
)
esb_timer_stop
();
/* Deregister */
misc_deregister
(
&
esb_miscdev
);
unregister_reboot_notifier
(
&
esb_notifier
);
iounmap
(
BASEADDR
);
pci_release_region
(
esb_pci
,
0
);
pci_disable_device
(
esb_pci
);
pci_dev_put
(
esb_pci
);
}
module_init
(
watchdog_init
);
module_exit
(
watchdog_cleanup
);
MODULE_AUTHOR
(
"Ross Biro and David Hrdeman"
);
MODULE_DESCRIPTION
(
"Watchdog driver for Intel 6300ESB chipsets"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
drivers/char/watchdog/ibmasr.c
0 → 100644
View file @
a8cd2e50
/*
* IBM Automatic Server Restart driver.
*
* Copyright (c) 2005 Andrey Panin <pazke@donpac.ru>
*
* Based on driver written by Pete Reynolds.
* Copyright (c) IBM Corporation, 1998-2004.
*
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
*/
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/dmi.h>
#include <asm/io.h>
#include <asm/uaccess.h>
enum
{
ASMTYPE_UNKNOWN
,
ASMTYPE_TOPAZ
,
ASMTYPE_JASPER
,
ASMTYPE_PEARL
,
ASMTYPE_JUNIPER
,
ASMTYPE_SPRUCE
,
};
#define PFX "ibmasr: "
#define TOPAZ_ASR_REG_OFFSET 4
#define TOPAZ_ASR_TOGGLE 0x40
#define TOPAZ_ASR_DISABLE 0x80
/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */
#define PEARL_BASE 0xe04
#define PEARL_WRITE 0xe06
#define PEARL_READ 0xe07
#define PEARL_ASR_DISABLE_MASK 0x80
/* bit 7: disable = 1, enable = 0 */
#define PEARL_ASR_TOGGLE_MASK 0x40
/* bit 6: 0, then 1, then 0 */
/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */
#define JASPER_ASR_REG_OFFSET 0x38
#define JASPER_ASR_DISABLE_MASK 0x01
/* bit 0: disable = 1, enable = 0 */
#define JASPER_ASR_TOGGLE_MASK 0x02
/* bit 1: 0, then 1, then 0 */
#define JUNIPER_BASE_ADDRESS 0x54b
/* Base address of Juniper ASR */
#define JUNIPER_ASR_DISABLE_MASK 0x01
/* bit 0: disable = 1 enable = 0 */
#define JUNIPER_ASR_TOGGLE_MASK 0x02
/* bit 1: 0, then 1, then 0 */
#define SPRUCE_BASE_ADDRESS 0x118e
/* Base address of Spruce ASR */
#define SPRUCE_ASR_DISABLE_MASK 0x01
/* bit 1: disable = 1 enable = 0 */
#define SPRUCE_ASR_TOGGLE_MASK 0x02
/* bit 0: 0, then 1, then 0 */
static
int
nowayout
=
WATCHDOG_NOWAYOUT
;
static
unsigned
long
asr_is_open
;
static
char
asr_expect_close
;
static
unsigned
int
asr_type
,
asr_base
,
asr_length
;
static
unsigned
int
asr_read_addr
,
asr_write_addr
;
static
unsigned
char
asr_toggle_mask
,
asr_disable_mask
;
static
void
asr_toggle
(
void
)
{
unsigned
char
reg
=
inb
(
asr_read_addr
);
outb
(
reg
&
~
asr_toggle_mask
,
asr_write_addr
);
reg
=
inb
(
asr_read_addr
);
outb
(
reg
|
asr_toggle_mask
,
asr_write_addr
);
reg
=
inb
(
asr_read_addr
);
outb
(
reg
&
~
asr_toggle_mask
,
asr_write_addr
);
reg
=
inb
(
asr_read_addr
);
}
static
void
asr_enable
(
void
)
{
unsigned
char
reg
;
if
(
asr_type
==
ASMTYPE_TOPAZ
)
{
/* asr_write_addr == asr_read_addr */
reg
=
inb
(
asr_read_addr
);
outb
(
reg
&
~
(
TOPAZ_ASR_TOGGLE
|
TOPAZ_ASR_DISABLE
),
asr_read_addr
);
}
else
{
/*
* First make sure the hardware timer is reset by toggling
* ASR hardware timer line.
*/
asr_toggle
();
reg
=
inb
(
asr_read_addr
);
outb
(
reg
&
~
asr_disable_mask
,
asr_write_addr
);
}
reg
=
inb
(
asr_read_addr
);
}
static
void
asr_disable
(
void
)
{
unsigned
char
reg
=
inb
(
asr_read_addr
);
if
(
asr_type
==
ASMTYPE_TOPAZ
)
/* asr_write_addr == asr_read_addr */
outb
(
reg
|
TOPAZ_ASR_TOGGLE
|
TOPAZ_ASR_DISABLE
,
asr_read_addr
);
else
{
outb
(
reg
|
asr_toggle_mask
,
asr_write_addr
);
reg
=
inb
(
asr_read_addr
);
outb
(
reg
|
asr_disable_mask
,
asr_write_addr
);
}
reg
=
inb
(
asr_read_addr
);
}
static
int
__init
asr_get_base_address
(
void
)
{
unsigned
char
low
,
high
;
const
char
*
type
=
""
;
asr_length
=
1
;
switch
(
asr_type
)
{
case
ASMTYPE_TOPAZ
:
/* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */
outb
(
0x07
,
0x2e
);
outb
(
0x07
,
0x2f
);
/* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */
outb
(
0x60
,
0x2e
);
high
=
inb
(
0x2f
);
/* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */
outb
(
0x61
,
0x2e
);
low
=
inb
(
0x2f
);
asr_base
=
(
high
<<
16
)
|
low
;
asr_read_addr
=
asr_write_addr
=
asr_base
+
TOPAZ_ASR_REG_OFFSET
;
asr_length
=
5
;
break
;
case
ASMTYPE_JASPER
:
type
=
"Jaspers "
;
/* FIXME: need to use pci_config_lock here, but it's not exported */
/* spin_lock_irqsave(&pci_config_lock, flags);*/
/* Select the SuperIO chip in the PCI I/O port register */
outl
(
0x8000f858
,
0xcf8
);
/*
* Read the base address for the SuperIO chip.
* Only the lower 16 bits are valid, but the address is word
* aligned so the last bit must be masked off.
*/
asr_base
=
inl
(
0xcfc
)
&
0xfffe
;
/* spin_unlock_irqrestore(&pci_config_lock, flags);*/
asr_read_addr
=
asr_write_addr
=
asr_base
+
JASPER_ASR_REG_OFFSET
;
asr_toggle_mask
=
JASPER_ASR_TOGGLE_MASK
;
asr_disable_mask
=
JASPER_ASR_DISABLE_MASK
;
asr_length
=
JASPER_ASR_REG_OFFSET
+
1
;
break
;
case
ASMTYPE_PEARL
:
type
=
"Pearls "
;
asr_base
=
PEARL_BASE
;
asr_read_addr
=
PEARL_READ
;
asr_write_addr
=
PEARL_WRITE
;
asr_toggle_mask
=
PEARL_ASR_TOGGLE_MASK
;
asr_disable_mask
=
PEARL_ASR_DISABLE_MASK
;
asr_length
=
4
;
break
;
case
ASMTYPE_JUNIPER
:
type
=
"Junipers "
;
asr_base
=
JUNIPER_BASE_ADDRESS
;
asr_read_addr
=
asr_write_addr
=
asr_base
;
asr_toggle_mask
=
JUNIPER_ASR_TOGGLE_MASK
;
asr_disable_mask
=
JUNIPER_ASR_DISABLE_MASK
;
break
;
case
ASMTYPE_SPRUCE
:
type
=
"Spruce's "
;
asr_base
=
SPRUCE_BASE_ADDRESS
;
asr_read_addr
=
asr_write_addr
=
asr_base
;
asr_toggle_mask
=
SPRUCE_ASR_TOGGLE_MASK
;
asr_disable_mask
=
SPRUCE_ASR_DISABLE_MASK
;
break
;
}
if
(
!
request_region
(
asr_base
,
asr_length
,
"ibmasr"
))
{
printk
(
KERN_ERR
PFX
"address %#x already in use
\n
"
,
asr_base
);
return
-
EBUSY
;
}
printk
(
KERN_INFO
PFX
"found %sASR @ addr %#x
\n
"
,
type
,
asr_base
);
return
0
;
}
static
ssize_t
asr_write
(
struct
file
*
file
,
const
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
asr_expect_close
=
0
;
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
asr_expect_close
=
42
;
}
}
asr_toggle
();
}
return
count
;
}
static
int
asr_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
static
const
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
identity
=
"IBM ASR"
};
void
__user
*
argp
=
(
void
__user
*
)
arg
;
int
__user
*
p
=
argp
;
int
heartbeat
;
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
,
p
);
case
WDIOC_KEEPALIVE
:
asr_toggle
();
return
0
;
/*
* The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
* and WDIOC_GETTIMEOUT always returns 256.
*/
case
WDIOC_GETTIMEOUT
:
heartbeat
=
256
;
return
put_user
(
heartbeat
,
p
);
case
WDIOC_SETOPTIONS
:
{
int
new_options
,
retval
=
-
EINVAL
;
if
(
get_user
(
new_options
,
p
))
return
-
EFAULT
;
if
(
new_options
&
WDIOS_DISABLECARD
)
{
asr_disable
();
retval
=
0
;
}
if
(
new_options
&
WDIOS_ENABLECARD
)
{
asr_enable
();
asr_toggle
();
retval
=
0
;
}
return
retval
;
}
}
return
-
ENOIOCTLCMD
;
}
static
int
asr_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
test_and_set_bit
(
0
,
&
asr_is_open
))
return
-
EBUSY
;
asr_toggle
();
asr_enable
();
return
nonseekable_open
(
inode
,
file
);
}
static
int
asr_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
asr_expect_close
==
42
)
asr_disable
();
else
{
printk
(
KERN_CRIT
PFX
"unexpected close, not stopping watchdog!
\n
"
);
asr_toggle
();
}
clear_bit
(
0
,
&
asr_is_open
);
asr_expect_close
=
0
;
return
0
;
}
static
struct
file_operations
asr_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
asr_write
,
.
ioctl
=
asr_ioctl
,
.
open
=
asr_open
,
.
release
=
asr_release
,
};
static
struct
miscdevice
asr_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
asr_fops
,
};
struct
ibmasr_id
{
const
char
*
desc
;
int
type
;
};
static
struct
ibmasr_id
__initdata
ibmasr_id_table
[]
=
{
{
"IBM Automatic Server Restart - eserver xSeries 220"
,
ASMTYPE_TOPAZ
},
{
"IBM Automatic Server Restart - Machine Type 8673"
,
ASMTYPE_PEARL
},
{
"IBM Automatic Server Restart - Machine Type 8480"
,
ASMTYPE_JASPER
},
{
"IBM Automatic Server Restart - Machine Type 8482"
,
ASMTYPE_JUNIPER
},
{
"IBM Automatic Server Restart - Machine Type 8648"
,
ASMTYPE_SPRUCE
},
{
NULL
}
};
static
int
__init
ibmasr_init
(
void
)
{
struct
ibmasr_id
*
id
;
int
rc
;
for
(
id
=
ibmasr_id_table
;
id
->
desc
;
id
++
)
{
if
(
dmi_find_device
(
DMI_DEV_TYPE_OTHER
,
id
->
desc
,
NULL
))
{
asr_type
=
id
->
type
;
break
;
}
}
if
(
!
asr_type
)
return
-
ENODEV
;
rc
=
misc_register
(
&
asr_miscdev
);
if
(
rc
<
0
)
{
printk
(
KERN_ERR
PFX
"failed to register misc device
\n
"
);
return
rc
;
}
rc
=
asr_get_base_address
();
if
(
rc
)
{
misc_deregister
(
&
asr_miscdev
);
return
rc
;
}
return
0
;
}
static
void
__exit
ibmasr_exit
(
void
)
{
if
(
!
nowayout
)
asr_disable
();
misc_deregister
(
&
asr_miscdev
);
release_region
(
asr_base
,
asr_length
);
}
module_init
(
ibmasr_init
);
module_exit
(
ibmasr_exit
);
module_param
(
nowayout
,
int
,
0
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
MODULE_DESCRIPTION
(
"IBM Automatic Server Restart driver"
);
MODULE_AUTHOR
(
"Andrey Panin"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
drivers/char/watchdog/mv64x60_wdt.c
0 → 100644
View file @
a8cd2e50
/*
* mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface
*
* Author: James Chapman <jchapman@katalix.com>
*
* Platform-specific setup code should configure the dog to generate
* interrupt or reset as required. This code only enables/disables
* and services the watchdog.
*
* Derived from mpc8xx_wdt.c, with the following copyright.
*
* 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/config.h>
#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/mv64x60.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/* MV64x60 WDC (config) register access definitions */
#define MV64x60_WDC_CTL1_MASK (3 << 24)
#define MV64x60_WDC_CTL1(val) ((val & 3) << 24)
#define MV64x60_WDC_CTL2_MASK (3 << 26)
#define MV64x60_WDC_CTL2(val) ((val & 3) << 26)
/* Flags bits */
#define MV64x60_WDOG_FLAG_OPENED 0
#define MV64x60_WDOG_FLAG_ENABLED 1
static
unsigned
long
wdt_flags
;
static
int
wdt_status
;
static
void
__iomem
*
mv64x60_regs
;
static
int
mv64x60_wdt_timeout
;
static
void
mv64x60_wdt_reg_write
(
u32
val
)
{
/* Allow write only to CTL1 / CTL2 fields, retaining values in
* other fields.
*/
u32
data
=
readl
(
mv64x60_regs
+
MV64x60_WDT_WDC
);
data
&=
~
(
MV64x60_WDC_CTL1_MASK
|
MV64x60_WDC_CTL2_MASK
);
data
|=
val
;
writel
(
data
,
mv64x60_regs
+
MV64x60_WDT_WDC
);
}
static
void
mv64x60_wdt_service
(
void
)
{
/* Write 01 followed by 10 to CTL2 */
mv64x60_wdt_reg_write
(
MV64x60_WDC_CTL2
(
0x01
));
mv64x60_wdt_reg_write
(
MV64x60_WDC_CTL2
(
0x02
));
}
static
void
mv64x60_wdt_handler_disable
(
void
)
{
if
(
test_and_clear_bit
(
MV64x60_WDOG_FLAG_ENABLED
,
&
wdt_flags
))
{
/* Write 01 followed by 10 to CTL1 */
mv64x60_wdt_reg_write
(
MV64x60_WDC_CTL1
(
0x01
));
mv64x60_wdt_reg_write
(
MV64x60_WDC_CTL1
(
0x02
));
printk
(
KERN_NOTICE
"mv64x60_wdt: watchdog deactivated
\n
"
);
}
}
static
void
mv64x60_wdt_handler_enable
(
void
)
{
if
(
!
test_and_set_bit
(
MV64x60_WDOG_FLAG_ENABLED
,
&
wdt_flags
))
{
/* Write 01 followed by 10 to CTL1 */
mv64x60_wdt_reg_write
(
MV64x60_WDC_CTL1
(
0x01
));
mv64x60_wdt_reg_write
(
MV64x60_WDC_CTL1
(
0x02
));
printk
(
KERN_NOTICE
"mv64x60_wdt: watchdog activated
\n
"
);
}
}
static
int
mv64x60_wdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
test_and_set_bit
(
MV64x60_WDOG_FLAG_OPENED
,
&
wdt_flags
))
return
-
EBUSY
;
mv64x60_wdt_service
();
mv64x60_wdt_handler_enable
();
return
0
;
}
static
int
mv64x60_wdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
mv64x60_wdt_service
();
#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
mv64x60_wdt_handler_disable
();
#endif
clear_bit
(
MV64x60_WDOG_FLAG_OPENED
,
&
wdt_flags
);
return
0
;
}
static
ssize_t
mv64x60_wdt_write
(
struct
file
*
file
,
const
char
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
if
(
*
ppos
!=
file
->
f_pos
)
return
-
ESPIPE
;
if
(
len
)
mv64x60_wdt_service
();
return
len
;
}
static
int
mv64x60_wdt_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
timeout
;
static
struct
watchdog_info
info
=
{
.
options
=
WDIOF_KEEPALIVEPING
,
.
firmware_version
=
0
,
.
identity
=
"MV64x60 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
:
mv64x60_wdt_service
();
wdt_status
|=
WDIOF_KEEPALIVEPING
;
break
;
case
WDIOC_SETTIMEOUT
:
return
-
EOPNOTSUPP
;
case
WDIOC_GETTIMEOUT
:
timeout
=
mv64x60_wdt_timeout
*
HZ
;
if
(
put_user
(
timeout
,
(
int
*
)
arg
))
return
-
EFAULT
;
break
;
default:
return
-
ENOIOCTLCMD
;
}
return
0
;
}
static
struct
file_operations
mv64x60_wdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
mv64x60_wdt_write
,
.
ioctl
=
mv64x60_wdt_ioctl
,
.
open
=
mv64x60_wdt_open
,
.
release
=
mv64x60_wdt_release
,
};
static
struct
miscdevice
mv64x60_wdt_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
mv64x60_wdt_fops
,
};
static
int
__devinit
mv64x60_wdt_probe
(
struct
device
*
dev
)
{
struct
platform_device
*
pd
=
to_platform_device
(
dev
);
struct
mv64x60_wdt_pdata
*
pdata
=
pd
->
dev
.
platform_data
;
int
bus_clk
=
133
;
mv64x60_wdt_timeout
=
10
;
if
(
pdata
)
{
mv64x60_wdt_timeout
=
pdata
->
timeout
;
bus_clk
=
pdata
->
bus_clk
;
}
mv64x60_regs
=
mv64x60_get_bridge_vbase
();
writel
((
mv64x60_wdt_timeout
*
(
bus_clk
*
1000000
))
>>
8
,
mv64x60_regs
+
MV64x60_WDT_WDC
);
return
misc_register
(
&
mv64x60_wdt_miscdev
);
}
static
int
__devexit
mv64x60_wdt_remove
(
struct
device
*
dev
)
{
misc_deregister
(
&
mv64x60_wdt_miscdev
);
mv64x60_wdt_service
();
mv64x60_wdt_handler_disable
();
return
0
;
}
static
struct
device_driver
mv64x60_wdt_driver
=
{
.
name
=
MV64x60_WDT_NAME
,
.
bus
=
&
platform_bus_type
,
.
probe
=
mv64x60_wdt_probe
,
.
remove
=
__devexit_p
(
mv64x60_wdt_remove
),
};
static
struct
platform_device
*
mv64x60_wdt_dev
;
static
int
__init
mv64x60_wdt_init
(
void
)
{
int
ret
;
printk
(
KERN_INFO
"MV64x60 watchdog driver
\n
"
);
mv64x60_wdt_dev
=
platform_device_register_simple
(
MV64x60_WDT_NAME
,
-
1
,
NULL
,
0
);
if
(
IS_ERR
(
mv64x60_wdt_dev
))
{
ret
=
PTR_ERR
(
mv64x60_wdt_dev
);
goto
out
;
}
ret
=
driver_register
(
&
mv64x60_wdt_driver
);
out:
return
ret
;
}
static
void
__exit
mv64x60_wdt_exit
(
void
)
{
driver_unregister
(
&
mv64x60_wdt_driver
);
platform_device_unregister
(
mv64x60_wdt_dev
);
}
module_init
(
mv64x60_wdt_init
);
module_exit
(
mv64x60_wdt_exit
);
MODULE_AUTHOR
(
"James Chapman <jchapman@katalix.com>"
);
MODULE_DESCRIPTION
(
"MV64x60 watchdog driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
drivers/char/watchdog/pcwd_pci.c
View file @
a8cd2e50
...
@@ -29,27 +29,29 @@
...
@@ -29,27 +29,29 @@
* Includes, defines, variables, module parameters, ...
* Includes, defines, variables, module parameters, ...
*/
*/
#include <linux/config.h>
#include <linux/config.h>
/* For CONFIG_WATCHDOG_NOWAYOUT/... */
#include <linux/module.h>
#include <linux/module.h>
/* For module specific items */
#include <linux/moduleparam.h>
#include <linux/moduleparam.h>
/* For new moduleparam's */
#include <linux/types.h>
#include <linux/types.h>
/* For standard types (like size_t) */
#include <linux/delay.h>
#include <linux/errno.h>
/* For the -ENODEV/... values */
#include <linux/miscdevice.h>
#include <linux/kernel.h>
/* For printk/panic/... */
#include <linux/watchdog.h>
#include <linux/delay.h>
/* For mdelay function */
#include <linux/notifier.h>
#include <linux/miscdevice.h>
/* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
#include <linux/reboot.h>
#include <linux/watchdog.h>
/* For the watchdog specific items */
#include <linux/init.h>
#include <linux/notifier.h>
/* For notifier support */
#include <linux/fs.h>
#include <linux/reboot.h>
/* For reboot_notifier stuff */
#include <linux/pci.h>
#include <linux/init.h>
/* For __init/__exit/... */
#include <linux/ioport.h>
#include <linux/fs.h>
/* For file operations */
#include <linux/spinlock.h>
#include <linux/pci.h>
/* For pci functions */
#include <linux/ioport.h>
/* For io-port access */
#include <asm/uaccess.h>
#include <linux/spinlock.h>
/* For spin_lock/spin_unlock/... */
#include <asm/io.h>
#include <asm/uaccess.h>
/* For copy_to_user/put_user/... */
#include <asm/io.h>
/* For inb/outb/... */
/* Module and version information */
/* Module and version information */
#define WATCHDOG_VERSION "1.01"
#define WATCHDOG_VERSION "1.01"
#define WATCHDOG_DATE "
15 Mar
2005"
#define WATCHDOG_DATE "
02 Sep
2005"
#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
#define WATCHDOG_NAME "pcwd_pci"
#define WATCHDOG_NAME "pcwd_pci"
#define PFX WATCHDOG_NAME ": "
#define PFX WATCHDOG_NAME ": "
...
@@ -335,12 +337,14 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
...
@@ -335,12 +337,14 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
return
-
EFAULT
;
return
-
EFAULT
;
if
(
new_options
&
WDIOS_DISABLECARD
)
{
if
(
new_options
&
WDIOS_DISABLECARD
)
{
pcipcwd_stop
();
if
(
pcipcwd_stop
())
return
-
EIO
;
retval
=
0
;
retval
=
0
;
}
}
if
(
new_options
&
WDIOS_ENABLECARD
)
{
if
(
new_options
&
WDIOS_ENABLECARD
)
{
pcipcwd_start
();
if
(
pcipcwd_start
())
return
-
EIO
;
retval
=
0
;
retval
=
0
;
}
}
...
...
drivers/char/watchdog/s3c2410_wdt.c
View file @
a8cd2e50
...
@@ -464,7 +464,7 @@ static void s3c2410wdt_shutdown(struct device *dev)
...
@@ -464,7 +464,7 @@ static void s3c2410wdt_shutdown(struct device *dev)
static
unsigned
long
wtcon_save
;
static
unsigned
long
wtcon_save
;
static
unsigned
long
wtdat_save
;
static
unsigned
long
wtdat_save
;
static
int
s3c2410wdt_suspend
(
struct
device
*
dev
,
u32
state
,
u32
level
)
static
int
s3c2410wdt_suspend
(
struct
device
*
dev
,
pm_message_t
state
,
u32
level
)
{
{
if
(
level
==
SUSPEND_POWER_DOWN
)
{
if
(
level
==
SUSPEND_POWER_DOWN
)
{
/* Save watchdog state, and turn it off. */
/* Save watchdog state, and turn it off. */
...
...
drivers/char/watchdog/sbc8360.c
0 → 100644
View file @
a8cd2e50
/*
* SBC8360 Watchdog driver
*
* (c) Copyright 2005 Webcon, Inc.
*
* Based on ib700wdt.c, which is based on advantechwdt.c which is based
* on acquirewdt.c which is based on wdt.c.
*
* (c) Copyright 2001 Charles Howes <chowes@vsol.net>
*
* Based on advantechwdt.c which is based on acquirewdt.c which
* is based on wdt.c.
*
* (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
*
* Based on acquirewdt.c which is based on wdt.c.
* Original copyright messages:
*
* (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
* http://www.redhat.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
*
* (c) Copyright 1995 Alan Cox <alan@redhat.com>
*
* 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
* Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
* Added timeout module option to override default
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/notifier.h>
#include <linux/fs.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
static
unsigned
long
sbc8360_is_open
;
static
spinlock_t
sbc8360_lock
;
static
char
expect_close
;
#define PFX "sbc8360: "
/*
*
* Watchdog Timer Configuration
*
* The function of the watchdog timer is to reset the system automatically
* and is defined at I/O port 0120H and 0121H. To enable the watchdog timer
* and allow the system to reset, write appropriate values from the table
* below to I/O port 0120H and 0121H. To disable the timer, write a zero
* value to I/O port 0121H for the system to stop the watchdog function.
*
* The following describes how the timer should be programmed (according to
* the vendor documentation)
*
* Enabling Watchdog:
* MOV AX,000AH (enable, phase I)
* MOV DX,0120H
* OUT DX,AX
* MOV AX,000BH (enable, phase II)
* MOV DX,0120H
* OUT DX,AX
* MOV AX,000nH (set multiplier n, from 1-4)
* MOV DX,0120H
* OUT DX,AX
* MOV AX,000mH (set base timer m, from 0-F)
* MOV DX,0121H
* OUT DX,AX
*
* Reset timer:
* MOV AX,000mH (same as set base timer, above)
* MOV DX,0121H
* OUT DX,AX
*
* Disabling Watchdog:
* MOV AX,0000H (a zero value)
* MOV DX,0120H
* OUT DX,AX
*
* Watchdog timeout configuration values:
* N
* M | 1 2 3 4
* --|----------------------------------
* 0 | 0.5s 5s 50s 100s
* 1 | 1s 10s 100s 200s
* 2 | 1.5s 15s 150s 300s
* 3 | 2s 20s 200s 400s
* 4 | 2.5s 25s 250s 500s
* 5 | 3s 30s 300s 600s
* 6 | 3.5s 35s 350s 700s
* 7 | 4s 40s 400s 800s
* 8 | 4.5s 45s 450s 900s
* 9 | 5s 50s 500s 1000s
* A | 5.5s 55s 550s 1100s
* B | 6s 60s 600s 1200s
* C | 6.5s 65s 650s 1300s
* D | 7s 70s 700s 1400s
* E | 7.5s 75s 750s 1500s
* F | 8s 80s 800s 1600s
*
* Another way to say the same things is:
* For N=1, Timeout = (M+1) * 0.5s
* For N=2, Timeout = (M+1) * 5s
* For N=3, Timeout = (M+1) * 50s
* For N=4, Timeout = (M+1) * 100s
*
*/
static
int
wd_times
[
64
][
2
]
=
{
{
0
,
1
},
/* 0 = 0.5s */
{
1
,
1
},
/* 1 = 1s */
{
2
,
1
},
/* 2 = 1.5s */
{
3
,
1
},
/* 3 = 2s */
{
4
,
1
},
/* 4 = 2.5s */
{
5
,
1
},
/* 5 = 3s */
{
6
,
1
},
/* 6 = 3.5s */
{
7
,
1
},
/* 7 = 4s */
{
8
,
1
},
/* 8 = 4.5s */
{
9
,
1
},
/* 9 = 5s */
{
0xA
,
1
},
/* 10 = 5.5s */
{
0xB
,
1
},
/* 11 = 6s */
{
0xC
,
1
},
/* 12 = 6.5s */
{
0xD
,
1
},
/* 13 = 7s */
{
0xE
,
1
},
/* 14 = 7.5s */
{
0xF
,
1
},
/* 15 = 8s */
{
0
,
2
},
/* 16 = 5s */
{
1
,
2
},
/* 17 = 10s */
{
2
,
2
},
/* 18 = 15s */
{
3
,
2
},
/* 19 = 20s */
{
4
,
2
},
/* 20 = 25s */
{
5
,
2
},
/* 21 = 30s */
{
6
,
2
},
/* 22 = 35s */
{
7
,
2
},
/* 23 = 40s */
{
8
,
2
},
/* 24 = 45s */
{
9
,
2
},
/* 25 = 50s */
{
0xA
,
2
},
/* 26 = 55s */
{
0xB
,
2
},
/* 27 = 60s */
{
0xC
,
2
},
/* 28 = 65s */
{
0xD
,
2
},
/* 29 = 70s */
{
0xE
,
2
},
/* 30 = 75s */
{
0xF
,
2
},
/* 31 = 80s */
{
0
,
3
},
/* 32 = 50s */
{
1
,
3
},
/* 33 = 100s */
{
2
,
3
},
/* 34 = 150s */
{
3
,
3
},
/* 35 = 200s */
{
4
,
3
},
/* 36 = 250s */
{
5
,
3
},
/* 37 = 300s */
{
6
,
3
},
/* 38 = 350s */
{
7
,
3
},
/* 39 = 400s */
{
8
,
3
},
/* 40 = 450s */
{
9
,
3
},
/* 41 = 500s */
{
0xA
,
3
},
/* 42 = 550s */
{
0xB
,
3
},
/* 43 = 600s */
{
0xC
,
3
},
/* 44 = 650s */
{
0xD
,
3
},
/* 45 = 700s */
{
0xE
,
3
},
/* 46 = 750s */
{
0xF
,
3
},
/* 47 = 800s */
{
0
,
4
},
/* 48 = 100s */
{
1
,
4
},
/* 49 = 200s */
{
2
,
4
},
/* 50 = 300s */
{
3
,
4
},
/* 51 = 400s */
{
4
,
4
},
/* 52 = 500s */
{
5
,
4
},
/* 53 = 600s */
{
6
,
4
},
/* 54 = 700s */
{
7
,
4
},
/* 55 = 800s */
{
8
,
4
},
/* 56 = 900s */
{
9
,
4
},
/* 57 = 1000s */
{
0xA
,
4
},
/* 58 = 1100s */
{
0xB
,
4
},
/* 59 = 1200s */
{
0xC
,
4
},
/* 60 = 1300s */
{
0xD
,
4
},
/* 61 = 1400s */
{
0xE
,
4
},
/* 62 = 1500s */
{
0xF
,
4
}
/* 63 = 1600s */
};
#define SBC8360_ENABLE 0x120
#define SBC8360_BASETIME 0x121
static
int
timeout
=
27
;
static
int
wd_margin
=
0xB
;
static
int
wd_multiplier
=
2
;
static
int
nowayout
=
WATCHDOG_NOWAYOUT
;
module_param
(
timeout
,
int
,
27
);
MODULE_PARM_DESC
(
timeout
,
"Index into timeout table (0-63) (default=27 (60s))"
);
module_param
(
nowayout
,
int
,
0
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
/*
* Kernel methods.
*/
/* Activate and pre-configure watchdog */
static
void
sbc8360_activate
(
void
)
{
/* Enable the watchdog */
outb
(
0x0A
,
SBC8360_ENABLE
);
msleep_interruptible
(
100
);
outb
(
0x0B
,
SBC8360_ENABLE
);
msleep_interruptible
(
100
);
/* Set timeout multiplier */
outb
(
wd_multiplier
,
SBC8360_ENABLE
);
msleep_interruptible
(
100
);
/* Nothing happens until first sbc8360_ping() */
}
/* Kernel pings watchdog */
static
void
sbc8360_ping
(
void
)
{
/* Write the base timer register */
outb
(
wd_margin
,
SBC8360_BASETIME
);
}
/* Userspace pings kernel driver, or requests clean close */
static
ssize_t
sbc8360_write
(
struct
file
*
file
,
const
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
expect_close
=
0
;
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
42
;
}
}
sbc8360_ping
();
}
return
count
;
}
static
int
sbc8360_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
spin_lock
(
&
sbc8360_lock
);
if
(
test_and_set_bit
(
0
,
&
sbc8360_is_open
))
{
spin_unlock
(
&
sbc8360_lock
);
return
-
EBUSY
;
}
if
(
nowayout
)
__module_get
(
THIS_MODULE
);
/* Activate and ping once to start the countdown */
spin_unlock
(
&
sbc8360_lock
);
sbc8360_activate
();
sbc8360_ping
();
return
nonseekable_open
(
inode
,
file
);
}
static
int
sbc8360_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
spin_lock
(
&
sbc8360_lock
);
if
(
expect_close
==
42
)
outb
(
0
,
SBC8360_ENABLE
);
else
printk
(
KERN_CRIT
PFX
"SBC8360 device closed unexpectedly. SBC8360 will not stop!
\n
"
);
clear_bit
(
0
,
&
sbc8360_is_open
);
expect_close
=
0
;
spin_unlock
(
&
sbc8360_lock
);
return
0
;
}
/*
* Notifier for system down
*/
static
int
sbc8360_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
/* Disable the SBC8360 Watchdog */
outb
(
0
,
SBC8360_ENABLE
);
}
return
NOTIFY_DONE
;
}
/*
* Kernel Interfaces
*/
static
struct
file_operations
sbc8360_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
sbc8360_write
,
.
open
=
sbc8360_open
,
.
release
=
sbc8360_close
,
};
static
struct
miscdevice
sbc8360_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
sbc8360_fops
,
};
/*
* The SBC8360 needs to learn about soft shutdowns in order to
* turn the timebomb registers off.
*/
static
struct
notifier_block
sbc8360_notifier
=
{
.
notifier_call
=
sbc8360_notify_sys
,
};
static
int
__init
sbc8360_init
(
void
)
{
int
res
;
unsigned
long
int
mseconds
=
60000
;
spin_lock_init
(
&
sbc8360_lock
);
res
=
misc_register
(
&
sbc8360_miscdev
);
if
(
res
)
{
printk
(
KERN_ERR
PFX
"failed to register misc device
\n
"
);
goto
out_nomisc
;
}
if
(
!
request_region
(
SBC8360_ENABLE
,
1
,
"SBC8360"
))
{
printk
(
KERN_ERR
PFX
"ENABLE method I/O %X is not available.
\n
"
,
SBC8360_ENABLE
);
res
=
-
EIO
;
goto
out_noenablereg
;
}
if
(
!
request_region
(
SBC8360_BASETIME
,
1
,
"SBC8360"
))
{
printk
(
KERN_ERR
PFX
"BASETIME method I/O %X is not available.
\n
"
,
SBC8360_BASETIME
);
res
=
-
EIO
;
goto
out_nobasetimereg
;
}
res
=
register_reboot_notifier
(
&
sbc8360_notifier
);
if
(
res
)
{
printk
(
KERN_ERR
PFX
"Failed to register reboot notifier.
\n
"
);
goto
out_noreboot
;
}
if
(
timeout
<
0
||
timeout
>
63
)
{
printk
(
KERN_ERR
PFX
"Invalid timeout index (must be 0-63).
\n
"
);
res
=
-
EINVAL
;
goto
out_noreboot
;
}
wd_margin
=
wd_times
[
timeout
][
0
];
wd_multiplier
=
wd_times
[
timeout
][
1
];
if
(
wd_multiplier
==
1
)
mseconds
=
(
wd_margin
+
1
)
*
500
;
else
if
(
wd_multiplier
==
2
)
mseconds
=
(
wd_margin
+
1
)
*
5000
;
else
if
(
wd_multiplier
==
3
)
mseconds
=
(
wd_margin
+
1
)
*
50000
;
else
if
(
wd_multiplier
==
4
)
mseconds
=
(
wd_margin
+
1
)
*
100000
;
/* My kingdom for the ability to print "0.5 seconds" in the kernel! */
printk
(
KERN_INFO
PFX
"Timeout set at %ld ms.
\n
"
,
mseconds
);
return
0
;
out_noreboot:
release_region
(
SBC8360_ENABLE
,
1
);
release_region
(
SBC8360_BASETIME
,
1
);
out_noenablereg:
out_nobasetimereg:
misc_deregister
(
&
sbc8360_miscdev
);
out_nomisc:
return
res
;
}
static
void
__exit
sbc8360_exit
(
void
)
{
misc_deregister
(
&
sbc8360_miscdev
);
unregister_reboot_notifier
(
&
sbc8360_notifier
);
release_region
(
SBC8360_ENABLE
,
1
);
release_region
(
SBC8360_BASETIME
,
1
);
}
module_init
(
sbc8360_init
);
module_exit
(
sbc8360_exit
);
MODULE_AUTHOR
(
"Ian E. Morgan <imorgan@webcon.ca>"
);
MODULE_DESCRIPTION
(
"SBC8360 watchdog driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_VERSION
(
"1.0"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
/* end of sbc8360.c */
drivers/char/watchdog/w83977f_wdt.c
0 → 100644
View file @
a8cd2e50
/*
* W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip
*
* (c) Copyright 2005 Jose Goncalves <jose.goncalves@inov.pt>
*
* Based on w83877f_wdt.c by Scott Jennings,
* and wdt977.c by Woody Suwalski
*
* -----------------------
*
* 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/moduleparam.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/watchdog.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define WATCHDOG_VERSION "1.00"
#define WATCHDOG_NAME "W83977F WDT"
#define PFX WATCHDOG_NAME ": "
#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
#define IO_INDEX_PORT 0x3F0
#define IO_DATA_PORT (IO_INDEX_PORT+1)
#define UNLOCK_DATA 0x87
#define LOCK_DATA 0xAA
#define DEVICE_REGISTER 0x07
#define DEFAULT_TIMEOUT 45
/* default timeout in seconds */
static
int
timeout
=
DEFAULT_TIMEOUT
;
static
int
timeoutW
;
/* timeout in watchdog counter units */
static
unsigned
long
timer_alive
;
static
int
testmode
;
static
char
expect_close
;
static
spinlock_t
spinlock
;
module_param
(
timeout
,
int
,
0
);
MODULE_PARM_DESC
(
timeout
,
"Watchdog timeout in seconds (15..7635), default="
__MODULE_STRING
(
DEFAULT_TIMEOUT
)
")"
);
module_param
(
testmode
,
int
,
0
);
MODULE_PARM_DESC
(
testmode
,
"Watchdog testmode (1 = no reboot), default=0"
);
static
int
nowayout
=
WATCHDOG_NOWAYOUT
;
module_param
(
nowayout
,
int
,
0
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
/*
* Start the watchdog
*/
static
int
wdt_start
(
void
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
spinlock
,
flags
);
/* Unlock the SuperIO chip */
outb_p
(
UNLOCK_DATA
,
IO_INDEX_PORT
);
outb_p
(
UNLOCK_DATA
,
IO_INDEX_PORT
);
/*
* Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
* F2 has the timeout in watchdog counter units.
* F3 is set to enable watchdog LED blink at timeout.
* F4 is used to just clear the TIMEOUT'ed state (bit 0).
*/
outb_p
(
DEVICE_REGISTER
,
IO_INDEX_PORT
);
outb_p
(
0x08
,
IO_DATA_PORT
);
outb_p
(
0xF2
,
IO_INDEX_PORT
);
outb_p
(
timeoutW
,
IO_DATA_PORT
);
outb_p
(
0xF3
,
IO_INDEX_PORT
);
outb_p
(
0x08
,
IO_DATA_PORT
);
outb_p
(
0xF4
,
IO_INDEX_PORT
);
outb_p
(
0x00
,
IO_DATA_PORT
);
/* Set device Aux2 active */
outb_p
(
0x30
,
IO_INDEX_PORT
);
outb_p
(
0x01
,
IO_DATA_PORT
);
/*
* Select device Aux1 (dev=7) to set GP16 as the watchdog output
* (in reg E6) and GP13 as the watchdog LED output (in reg E3).
* Map GP16 at pin 119.
* In test mode watch the bit 0 on F4 to indicate "triggered" or
* check watchdog LED on SBC.
*/
outb_p
(
DEVICE_REGISTER
,
IO_INDEX_PORT
);
outb_p
(
0x07
,
IO_DATA_PORT
);
if
(
!
testmode
)
{
unsigned
pin_map
;
outb_p
(
0xE6
,
IO_INDEX_PORT
);
outb_p
(
0x0A
,
IO_DATA_PORT
);
outb_p
(
0x2C
,
IO_INDEX_PORT
);
pin_map
=
inb_p
(
IO_DATA_PORT
);
pin_map
|=
0x10
;
pin_map
&=
~
(
0x20
);
outb_p
(
0x2C
,
IO_INDEX_PORT
);
outb_p
(
pin_map
,
IO_DATA_PORT
);
}
outb_p
(
0xE3
,
IO_INDEX_PORT
);
outb_p
(
0x08
,
IO_DATA_PORT
);
/* Set device Aux1 active */
outb_p
(
0x30
,
IO_INDEX_PORT
);
outb_p
(
0x01
,
IO_DATA_PORT
);
/* Lock the SuperIO chip */
outb_p
(
LOCK_DATA
,
IO_INDEX_PORT
);
spin_unlock_irqrestore
(
&
spinlock
,
flags
);
printk
(
KERN_INFO
PFX
"activated.
\n
"
);
return
0
;
}
/*
* Stop the watchdog
*/
static
int
wdt_stop
(
void
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
spinlock
,
flags
);
/* Unlock the SuperIO chip */
outb_p
(
UNLOCK_DATA
,
IO_INDEX_PORT
);
outb_p
(
UNLOCK_DATA
,
IO_INDEX_PORT
);
/*
* Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
* F2 is reset to its default value (watchdog timer disabled).
* F3 is reset to its default state.
* F4 clears the TIMEOUT'ed state (bit 0) - back to default.
*/
outb_p
(
DEVICE_REGISTER
,
IO_INDEX_PORT
);
outb_p
(
0x08
,
IO_DATA_PORT
);
outb_p
(
0xF2
,
IO_INDEX_PORT
);
outb_p
(
0xFF
,
IO_DATA_PORT
);
outb_p
(
0xF3
,
IO_INDEX_PORT
);
outb_p
(
0x00
,
IO_DATA_PORT
);
outb_p
(
0xF4
,
IO_INDEX_PORT
);
outb_p
(
0x00
,
IO_DATA_PORT
);
outb_p
(
0xF2
,
IO_INDEX_PORT
);
outb_p
(
0x00
,
IO_DATA_PORT
);
/*
* Select device Aux1 (dev=7) to set GP16 (in reg E6) and
* Gp13 (in reg E3) as inputs.
*/
outb_p
(
DEVICE_REGISTER
,
IO_INDEX_PORT
);
outb_p
(
0x07
,
IO_DATA_PORT
);
if
(
!
testmode
)
{
outb_p
(
0xE6
,
IO_INDEX_PORT
);
outb_p
(
0x01
,
IO_DATA_PORT
);
}
outb_p
(
0xE3
,
IO_INDEX_PORT
);
outb_p
(
0x01
,
IO_DATA_PORT
);
/* Lock the SuperIO chip */
outb_p
(
LOCK_DATA
,
IO_INDEX_PORT
);
spin_unlock_irqrestore
(
&
spinlock
,
flags
);
printk
(
KERN_INFO
PFX
"shutdown.
\n
"
);
return
0
;
}
/*
* Send a keepalive ping to the watchdog
* This is done by simply re-writing the timeout to reg. 0xF2
*/
static
int
wdt_keepalive
(
void
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
spinlock
,
flags
);
/* Unlock the SuperIO chip */
outb_p
(
UNLOCK_DATA
,
IO_INDEX_PORT
);
outb_p
(
UNLOCK_DATA
,
IO_INDEX_PORT
);
/* Select device Aux2 (device=8) to kick watchdog reg F2 */
outb_p
(
DEVICE_REGISTER
,
IO_INDEX_PORT
);
outb_p
(
0x08
,
IO_DATA_PORT
);
outb_p
(
0xF2
,
IO_INDEX_PORT
);
outb_p
(
timeoutW
,
IO_DATA_PORT
);
/* Lock the SuperIO chip */
outb_p
(
LOCK_DATA
,
IO_INDEX_PORT
);
spin_unlock_irqrestore
(
&
spinlock
,
flags
);
return
0
;
}
/*
* Set the watchdog timeout value
*/
static
int
wdt_set_timeout
(
int
t
)
{
int
tmrval
;
/*
* Convert seconds to watchdog counter time units, rounding up.
* On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup
* value. This information is supplied in the PCM-5335 manual and was
* checked by me on a real board. This is a bit strange because W83977f
* datasheet says counter unit is in minutes!
*/
if
(
t
<
15
)
return
-
EINVAL
;
tmrval
=
((
t
+
15
)
+
29
)
/
30
;
if
(
tmrval
>
255
)
return
-
EINVAL
;
/*
* timeout is the timeout in seconds,
* timeoutW is the timeout in watchdog counter units.
*/
timeoutW
=
tmrval
;
timeout
=
(
timeoutW
*
30
)
-
15
;
return
0
;
}
/*
* Get the watchdog status
*/
static
int
wdt_get_status
(
int
*
status
)
{
int
new_status
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
spinlock
,
flags
);
/* Unlock the SuperIO chip */
outb_p
(
UNLOCK_DATA
,
IO_INDEX_PORT
);
outb_p
(
UNLOCK_DATA
,
IO_INDEX_PORT
);
/* Select device Aux2 (device=8) to read watchdog reg F4 */
outb_p
(
DEVICE_REGISTER
,
IO_INDEX_PORT
);
outb_p
(
0x08
,
IO_DATA_PORT
);
outb_p
(
0xF4
,
IO_INDEX_PORT
);
new_status
=
inb_p
(
IO_DATA_PORT
);
/* Lock the SuperIO chip */
outb_p
(
LOCK_DATA
,
IO_INDEX_PORT
);
spin_unlock_irqrestore
(
&
spinlock
,
flags
);
*
status
=
0
;
if
(
new_status
&
1
)
*
status
|=
WDIOF_CARDRESET
;
return
0
;
}
/*
* /dev/watchdog handling
*/
static
int
wdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/* If the watchdog is alive we don't need to start it again */
if
(
test_and_set_bit
(
0
,
&
timer_alive
)
)
return
-
EBUSY
;
if
(
nowayout
)
__module_get
(
THIS_MODULE
);
wdt_start
();
return
nonseekable_open
(
inode
,
file
);
}
static
int
wdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/*
* Shut off the timer.
* Lock it in if it's a module and we set nowayout
*/
if
(
expect_close
==
42
)
{
wdt_stop
();
clear_bit
(
0
,
&
timer_alive
);
}
else
{
wdt_keepalive
();
printk
(
KERN_CRIT
PFX
"unexpected close, not stopping watchdog!
\n
"
);
}
expect_close
=
0
;
return
0
;
}
/*
* wdt_write:
* @file: file handle to the watchdog
* @buf: buffer to write (unused as data does not matter here
* @count: count of bytes
* @ppos: pointer to the position to write. No seeks allowed
*
* A write to a watchdog device is defined as a keepalive signal. Any
* write of data will do, as we we don't define content meaning.
*/
static
ssize_t
wdt_write
(
struct
file
*
file
,
const
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
/* See if we got the magic character 'V' and reload the timer */
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
ofs
;
/* note: just in case someone wrote the magic character long ago */
expect_close
=
0
;
/* scan to see whether or not we got the magic character */
for
(
ofs
=
0
;
ofs
!=
count
;
ofs
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
ofs
))
return
-
EFAULT
;
if
(
c
==
'V'
)
{
expect_close
=
42
;
}
}
}
/* someone wrote to us, we should restart timer */
wdt_keepalive
();
}
return
count
;
}
/*
* wdt_ioctl:
* @inode: inode of the device
* @file: file handle to the device
* @cmd: watchdog command
* @arg: argument pointer
*
* The watchdog API defines a common set of functions for all watchdogs
* according to their available features.
*/
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
|
WDIOF_KEEPALIVEPING
,
.
firmware_version
=
1
,
.
identity
=
WATCHDOG_NAME
,
};
static
int
wdt_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
status
;
int
new_options
,
retval
=
-
EINVAL
;
int
new_timeout
;
union
{
struct
watchdog_info
__user
*
ident
;
int
__user
*
i
;
}
uarg
;
uarg
.
i
=
(
int
__user
*
)
arg
;
switch
(
cmd
)
{
default:
return
-
ENOIOCTLCMD
;
case
WDIOC_GETSUPPORT
:
return
copy_to_user
(
uarg
.
ident
,
&
ident
,
sizeof
(
ident
))
?
-
EFAULT
:
0
;
case
WDIOC_GETSTATUS
:
wdt_get_status
(
&
status
);
return
put_user
(
status
,
uarg
.
i
);
case
WDIOC_GETBOOTSTATUS
:
return
put_user
(
0
,
uarg
.
i
);
case
WDIOC_KEEPALIVE
:
wdt_keepalive
();
return
0
;
case
WDIOC_SETOPTIONS
:
if
(
get_user
(
new_options
,
uarg
.
i
))
return
-
EFAULT
;
if
(
new_options
&
WDIOS_DISABLECARD
)
{
wdt_stop
();
retval
=
0
;
}
if
(
new_options
&
WDIOS_ENABLECARD
)
{
wdt_start
();
retval
=
0
;
}
return
retval
;
case
WDIOC_SETTIMEOUT
:
if
(
get_user
(
new_timeout
,
uarg
.
i
))
return
-
EFAULT
;
if
(
wdt_set_timeout
(
new_timeout
))
return
-
EINVAL
;
wdt_keepalive
();
/* Fall */
case
WDIOC_GETTIMEOUT
:
return
put_user
(
timeout
,
uarg
.
i
);
}
}
static
int
wdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
wdt_stop
();
return
NOTIFY_DONE
;
}
static
struct
file_operations
wdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
wdt_write
,
.
ioctl
=
wdt_ioctl
,
.
open
=
wdt_open
,
.
release
=
wdt_release
,
};
static
struct
miscdevice
wdt_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
wdt_fops
,
};
static
struct
notifier_block
wdt_notifier
=
{
.
notifier_call
=
wdt_notify_sys
,
};
static
int
__init
w83977f_wdt_init
(
void
)
{
int
rc
;
printk
(
KERN_INFO
PFX
DRIVER_VERSION
);
spin_lock_init
(
&
spinlock
);
/*
* Check that the timeout value is within it's range ;
* if not reset to the default
*/
if
(
wdt_set_timeout
(
timeout
))
{
wdt_set_timeout
(
DEFAULT_TIMEOUT
);
printk
(
KERN_INFO
PFX
"timeout value must be 15<=timeout<=7635, using %d
\n
"
,
DEFAULT_TIMEOUT
);
}
if
(
!
request_region
(
IO_INDEX_PORT
,
2
,
WATCHDOG_NAME
))
{
printk
(
KERN_ERR
PFX
"I/O address 0x%04x already in use
\n
"
,
IO_INDEX_PORT
);
rc
=
-
EIO
;
goto
err_out
;
}
rc
=
misc_register
(
&
wdt_miscdev
);
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"cannot register miscdev on minor=%d (err=%d)
\n
"
,
wdt_miscdev
.
minor
,
rc
);
goto
err_out_region
;
}
rc
=
register_reboot_notifier
(
&
wdt_notifier
);
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"cannot register reboot notifier (err=%d)
\n
"
,
rc
);
goto
err_out_miscdev
;
}
printk
(
KERN_INFO
PFX
"initialized. timeout=%d sec (nowayout=%d testmode=%d)
\n
"
,
timeout
,
nowayout
,
testmode
);
return
0
;
err_out_miscdev:
misc_deregister
(
&
wdt_miscdev
);
err_out_region:
release_region
(
IO_INDEX_PORT
,
2
);
err_out:
return
rc
;
}
static
void
__exit
w83977f_wdt_exit
(
void
)
{
wdt_stop
();
misc_deregister
(
&
wdt_miscdev
);
unregister_reboot_notifier
(
&
wdt_notifier
);
release_region
(
IO_INDEX_PORT
,
2
);
}
module_init
(
w83977f_wdt_init
);
module_exit
(
w83977f_wdt_exit
);
MODULE_AUTHOR
(
"Jose Goncalves <jose.goncalves@inov.pt>"
);
MODULE_DESCRIPTION
(
"Driver for watchdog timer in W83977F I/O chip"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
include/asm-ppc/mv64x60.h
View file @
a8cd2e50
...
@@ -119,6 +119,14 @@ extern spinlock_t mv64x60_lock;
...
@@ -119,6 +119,14 @@ extern spinlock_t mv64x60_lock;
#define MV64x60_64BIT_WIN_COUNT 24
#define MV64x60_64BIT_WIN_COUNT 24
/* Watchdog Platform Device, Driver Data */
#define MV64x60_WDT_NAME "wdt"
struct
mv64x60_wdt_pdata
{
int
timeout
;
/* watchdog expiry in seconds, default 10 */
int
bus_clk
;
/* bus clock in MHz, default 133 */
};
/*
/*
* Define a structure that's used to pass in config information to the
* Define a structure that's used to pass in config information to the
* core routines.
* core routines.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment