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
nexedi
linux
Commits
4896f66e
Commit
4896f66e
authored
Oct 20, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linux-watchdog.bkbits.net/linux-2.6-watchdog
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
178f5312
ae6d9652
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
552 additions
and
4 deletions
+552
-4
arch/arm/configs/bast_defconfig
arch/arm/configs/bast_defconfig
+9
-2
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/s3c2410_defconfig
+8
-1
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Kconfig
+16
-0
drivers/char/watchdog/Makefile
drivers/char/watchdog/Makefile
+1
-0
drivers/char/watchdog/i8xx_tco.c
drivers/char/watchdog/i8xx_tco.c
+1
-1
drivers/char/watchdog/s3c2410_wdt.c
drivers/char/watchdog/s3c2410_wdt.c
+516
-0
include/asm-arm/arch-s3c2410/regs-watchdog.h
include/asm-arm/arch-s3c2410/regs-watchdog.h
+1
-0
No files found.
arch/arm/configs/bast_defconfig
View file @
4896f66e
...
...
@@ -479,12 +479,19 @@ CONFIG_PPDEV=y
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
#
# Watchdog Device Drivers
#
# CONFIG_SOFT_WATCHDOG is not set
CONFIG_S3C2410_WATCHDOG=y
# CONFIG_NVRAM is not set
CONFIG_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
...
...
arch/arm/configs/s3c2410_defconfig
View file @
4896f66e
...
...
@@ -493,7 +493,14 @@ CONFIG_PPDEV=y
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
#
# Watchdog Device Drivers
#
# CONFIG_SOFT_WATCHDOG is not set
CONFIG_S3C2410_WATCHDOG=y
# CONFIG_NVRAM is not set
CONFIG_RTC=y
# CONFIG_DTLK is not set
...
...
drivers/char/watchdog/Kconfig
View file @
4896f66e
...
...
@@ -106,6 +106,22 @@ config IXP2000_WATCHDOG
Say N if you are unsure.
config S3C2410_WATCHDOG
tristate "S3C2410 Watchdog"
depends on WATCHDOG && ARCH_S3C2410
help
Watchdog timer block in the Samsung S3C2410 chips. This will
reboot the system when the timer expires with the watchdog
enabled.
The driver is limited by the speed of the system's PCLK
signal, so with reasonbaly fast systems (PCLK around 50-66MHz)
then watchdog intervals of over approximately 20seconds are
unavailable.
The driver can be built as a module by choosing M, and will
be called s3c2410_wdt
config SA1100_WATCHDOG
tristate "SA1100/PXA2xx watchdog"
depends on WATCHDOG && ( ARCH_SA1100 || ARCH_PXA )
...
...
drivers/char/watchdog/Makefile
View file @
4896f66e
...
...
@@ -21,6 +21,7 @@ obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_I8XX_TCO)
+=
i8xx_tco.o
obj-$(CONFIG_MACHZ_WDT)
+=
machzwd.o
obj-$(CONFIG_SH_WDT)
+=
shwdt.o
obj-$(CONFIG_S3C2410_WATCHDOG)
+=
s3c2410_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG)
+=
sa1100_wdt.o
obj-$(CONFIG_EUROTECH_WDT)
+=
eurotechwdt.o
obj-$(CONFIG_SOFT_WATCHDOG)
+=
softdog.o
...
...
drivers/char/watchdog/i8xx_tco.c
View file @
4896f66e
...
...
@@ -465,7 +465,7 @@ static int __init watchdog_init (void)
goto
unreg_notifier
;
}
tco_timer_
keepalive
();
tco_timer_
stop
();
printk
(
KERN_INFO
PFX
"initialized (0x%04x). heartbeat=%d sec (nowayout=%d)
\n
"
,
TCOBASE
,
heartbeat
,
nowayout
);
...
...
drivers/char/watchdog/s3c2410_wdt.c
0 → 100644
View file @
4896f66e
/* linux/drivers/char/watchdog/s3c2410_wdt.c
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 Watchdog Timer Support
*
* Based on, softdog.c by Alan Cox,
* (c) Copyright 1996 Alan Cox <alan@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.
*
* 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., 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
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/arch/map.h>
#include <asm/hardware/clock.h>
#undef S3C2410_VA_WATCHDOG
#define S3C2410_VA_WATCHDOG (0)
#include <asm/arch/regs-watchdog.h>
#define PFX "s3c2410-wdt: "
#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
nowayout
=
1
;
#else
static
int
nowayout
=
0
;
#endif
static
int
tmr_margin
=
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME
;
static
int
tmr_atboot
=
CONFIG_S3C2410_WATCHDOG_ATBOOT
;
static
int
soft_noboot
=
0
;
static
int
debug
=
0
;
module_param
(
tmr_margin
,
int
,
0
);
module_param
(
tmr_atboot
,
int
,
0
);
module_param
(
nowayout
,
int
,
0
);
module_param
(
soft_noboot
,
int
,
0
);
module_param
(
debug
,
int
,
0
);
MODULE_PARM_DESC
(
tmr_margin
,
"Watchdog tmr_margin in seconds. default="
__MODULE_STRING
(
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME
)
")"
);
MODULE_PARM_DESC
(
tmr_atboot
,
"Watchdog is started at boot time if set to 1, default="
__MODULE_STRING
(
CONFIG_S3C2410_WATCHDOG_ATBOOT
));
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
MODULE_PARM_DESC
(
soft_noboot
,
"Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)"
);
MODULE_PARM_DESC
(
debug
,
"Watchdog debug, set to >1 for debug, (default 0)"
);
typedef
enum
close_state
{
CLOSE_STATE_NOT
,
CLOSE_STATE_ALLOW
=
0x4021
}
close_state_t
;
static
DECLARE_MUTEX
(
open_lock
);
static
struct
resource
*
wdt_mem
;
static
struct
resource
*
wdt_irq
;
static
struct
clk
*
wdt_clock
;
static
void
__iomem
*
wdt_base
;
static
unsigned
int
wdt_count
;
static
close_state_t
allow_close
;
/* watchdog control routines */
#define DBG(msg...) do { \
if (debug) \
printk(KERN_INFO msg); \
} while(0)
/* functions */
static
int
s3c2410wdt_keepalive
(
void
)
{
writel
(
wdt_count
,
wdt_base
+
S3C2410_WTCNT
);
return
0
;
}
static
int
s3c2410wdt_stop
(
void
)
{
unsigned
long
wtcon
;
wtcon
=
readl
(
wdt_base
+
S3C2410_WTCON
);
wtcon
&=
~
(
S3C2410_WTCON_ENABLE
|
S3C2410_WTCON_RSTEN
);
writel
(
wtcon
,
wdt_base
+
S3C2410_WTCON
);
return
0
;
}
static
int
s3c2410wdt_start
(
void
)
{
unsigned
long
wtcon
;
s3c2410wdt_stop
();
wtcon
=
readl
(
wdt_base
+
S3C2410_WTCON
);
wtcon
|=
S3C2410_WTCON_ENABLE
|
S3C2410_WTCON_DIV128
;
if
(
soft_noboot
)
{
wtcon
|=
S3C2410_WTCON_INTEN
;
wtcon
&=
~
S3C2410_WTCON_RSTEN
;
}
else
{
wtcon
&=
~
S3C2410_WTCON_INTEN
;
wtcon
|=
S3C2410_WTCON_RSTEN
;
}
DBG
(
"%s: wdt_count=0x%08x, wtcon=%08lx
\n
"
,
__FUNCTION__
,
wdt_count
,
wtcon
);
writel
(
wdt_count
,
wdt_base
+
S3C2410_WTDAT
);
writel
(
wdt_count
,
wdt_base
+
S3C2410_WTCNT
);
writel
(
wtcon
,
wdt_base
+
S3C2410_WTCON
);
return
0
;
}
static
int
s3c2410wdt_set_heartbeat
(
int
timeout
)
{
unsigned
int
freq
=
clk_get_rate
(
wdt_clock
);
unsigned
int
count
;
unsigned
int
divisor
=
1
;
unsigned
long
wtcon
;
if
(
timeout
<
1
)
return
-
EINVAL
;
/* I think someone must have missed a divide-by-2 in the 2410,
* as a divisor of 128 gives half the calculated delay...
*/
freq
/=
128
/
2
;
count
=
timeout
*
freq
;
DBG
(
"%s: count=%d, timeout=%d, freq=%d
\n
"
,
__FUNCTION__
,
count
,
timeout
,
freq
);
/* if the count is bigger than the watchdog register,
then work out what we need to do (and if) we can
actually make this value
*/
if
(
count
>=
0x10000
)
{
for
(
divisor
=
1
;
divisor
<=
0x100
;
divisor
++
)
{
if
((
count
/
divisor
)
<
0x10000
)
break
;
}
if
((
count
/
divisor
)
>=
0x10000
)
{
printk
(
KERN_ERR
PFX
"timeout %d too big
\n
"
,
timeout
);
return
-
EINVAL
;
}
}
tmr_margin
=
timeout
;
DBG
(
"%s: timeout=%d, divisor=%d, count=%d (%08x)
\n
"
,
__FUNCTION__
,
timeout
,
divisor
,
count
,
count
/
divisor
);
count
/=
divisor
;
wdt_count
=
count
;
/* update the pre-scaler */
wtcon
=
readl
(
wdt_base
+
S3C2410_WTCON
);
wtcon
&=
~
S3C2410_WTCON_PRESCALE_MASK
;
wtcon
|=
S3C2410_WTCON_PRESCALE
(
divisor
-
1
);
writel
(
count
,
wdt_base
+
S3C2410_WTDAT
);
writel
(
wtcon
,
wdt_base
+
S3C2410_WTCON
);
return
0
;
}
/*
* /dev/watchdog handling
*/
static
int
s3c2410wdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
down_trylock
(
&
open_lock
))
return
-
EBUSY
;
if
(
nowayout
)
{
__module_get
(
THIS_MODULE
);
}
else
{
allow_close
=
CLOSE_STATE_ALLOW
;
}
/* start the timer */
s3c2410wdt_start
();
return
nonseekable_open
(
inode
,
file
);
}
static
int
s3c2410wdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/*
* Shut off the timer.
* Lock it in if it's a module and we set nowayout
*/
if
(
allow_close
==
CLOSE_STATE_ALLOW
)
{
s3c2410wdt_stop
();
}
else
{
printk
(
KERN_CRIT
PFX
"Unexpected close, not stopping watchdog!
\n
"
);
s3c2410wdt_keepalive
();
}
allow_close
=
CLOSE_STATE_NOT
;
up
(
&
open_lock
);
return
0
;
}
static
ssize_t
s3c2410wdt_write
(
struct
file
*
file
,
const
char
__user
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
/*
* Refresh the timer.
*/
if
(
len
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
allow_close
=
CLOSE_STATE_NOT
;
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
allow_close
=
CLOSE_STATE_ALLOW
;
}
}
s3c2410wdt_keepalive
();
}
return
len
;
}
#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
static
struct
watchdog_info
s3c2410_wdt_ident
=
{
.
options
=
OPTIONS
,
.
firmware_version
=
0
,
.
identity
=
"S3C2410 Watchdog"
,
};
static
int
s3c2410wdt_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
void
__user
*
argp
=
(
void
__user
*
)
arg
;
int
__user
*
p
=
argp
;
int
new_margin
;
switch
(
cmd
)
{
default:
return
-
ENOIOCTLCMD
;
case
WDIOC_GETSUPPORT
:
return
copy_to_user
(
argp
,
&
s3c2410_wdt_ident
,
sizeof
(
s3c2410_wdt_ident
))
?
-
EFAULT
:
0
;
case
WDIOC_GETSTATUS
:
case
WDIOC_GETBOOTSTATUS
:
return
put_user
(
0
,
p
);
case
WDIOC_KEEPALIVE
:
s3c2410wdt_keepalive
();
return
0
;
case
WDIOC_SETTIMEOUT
:
if
(
get_user
(
new_margin
,
p
))
return
-
EFAULT
;
if
(
s3c2410wdt_set_heartbeat
(
new_margin
))
return
-
EINVAL
;
s3c2410wdt_keepalive
();
return
put_user
(
tmr_margin
,
p
);
case
WDIOC_GETTIMEOUT
:
return
put_user
(
tmr_margin
,
p
);
}
}
/*
* Notifier for system down
*/
static
int
s3c2410wdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
/* Turn the WDT off */
s3c2410wdt_stop
();
}
return
NOTIFY_DONE
;
}
/* kernel interface */
static
struct
file_operations
s3c2410wdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
s3c2410wdt_write
,
.
ioctl
=
s3c2410wdt_ioctl
,
.
open
=
s3c2410wdt_open
,
.
release
=
s3c2410wdt_release
,
};
static
struct
miscdevice
s3c2410wdt_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
s3c2410wdt_fops
,
};
static
struct
notifier_block
s3c2410wdt_notifier
=
{
.
notifier_call
=
s3c2410wdt_notify_sys
,
};
/* interrupt handler code */
static
irqreturn_t
s3c2410wdt_irq
(
int
irqno
,
void
*
param
,
struct
pt_regs
*
regs
)
{
printk
(
KERN_INFO
PFX
"Watchdog timer expired!
\n
"
);
s3c2410wdt_keepalive
();
return
IRQ_HANDLED
;
}
/* device interface */
static
int
s3c2410wdt_probe
(
struct
device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
resource
*
res
;
int
started
=
0
;
int
ret
;
int
size
;
DBG
(
"%s: probe=%p, device=%p
\n
"
,
__FUNCTION__
,
pdev
,
dev
);
/* get the memory region for the watchdog timer */
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
res
==
NULL
)
{
printk
(
KERN_INFO
PFX
"failed to get memory region resouce
\n
"
);
return
-
ENOENT
;
}
size
=
(
res
->
end
-
res
->
start
)
+
1
;
wdt_mem
=
request_mem_region
(
res
->
start
,
size
,
pdev
->
name
);
if
(
wdt_mem
==
NULL
)
{
printk
(
KERN_INFO
PFX
"failed to get memory region
\n
"
);
return
-
ENOENT
;
}
wdt_base
=
ioremap
(
res
->
start
,
size
);
if
(
wdt_base
==
0
)
{
printk
(
KERN_INFO
PFX
"failed to ioremap() region
\n
"
);
return
-
EINVAL
;
}
DBG
(
"probe: mapped wdt_base=%p
\n
"
,
wdt_base
);
res
=
platform_get_resource
(
pdev
,
IORESOURCE_IRQ
,
0
);
if
(
res
==
NULL
)
{
printk
(
KERN_INFO
PFX
"failed to get irq resource
\n
"
);
return
-
ENOENT
;
}
ret
=
request_irq
(
res
->
start
,
s3c2410wdt_irq
,
0
,
pdev
->
name
,
dev
);
if
(
ret
!=
0
)
{
printk
(
KERN_INFO
PFX
"failed to install irq (%d)
\n
"
,
ret
);
return
ret
;
}
wdt_clock
=
clk_get
(
dev
,
"watchdog"
);
if
(
wdt_clock
==
NULL
)
{
printk
(
KERN_INFO
PFX
"failed to find watchdog clock source
\n
"
);
return
-
ENOENT
;
}
clk_use
(
wdt_clock
);
clk_enable
(
wdt_clock
);
/* see if we can actually set the requested timer margin, and if
* not, try the default value */
if
(
s3c2410wdt_set_heartbeat
(
tmr_margin
))
{
started
=
s3c2410wdt_set_heartbeat
(
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME
);
if
(
started
==
0
)
{
printk
(
KERN_INFO
PFX
"tmr_margin value out of range, default %d used
\n
"
,
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME
);
}
else
{
printk
(
KERN_INFO
PFX
"default timer value is out of range, cannot start
\n
"
);
}
}
ret
=
register_reboot_notifier
(
&
s3c2410wdt_notifier
);
if
(
ret
)
{
printk
(
KERN_ERR
PFX
"cannot register reboot notifier (%d)
\n
"
,
ret
);
return
ret
;
}
ret
=
misc_register
(
&
s3c2410wdt_miscdev
);
if
(
ret
)
{
printk
(
KERN_ERR
PFX
"cannot register miscdev on minor=%d (%d)
\n
"
,
WATCHDOG_MINOR
,
ret
);
unregister_reboot_notifier
(
&
s3c2410wdt_notifier
);
return
ret
;
}
if
(
tmr_atboot
&&
started
==
0
)
{
printk
(
KERN_INFO
PFX
"Starting Watchdog Timer
\n
"
);
s3c2410wdt_start
();
}
return
0
;
}
static
int
s3c2410wdt_remove
(
struct
device
*
dev
)
{
if
(
wdt_mem
!=
NULL
)
{
release_resource
(
wdt_mem
);
kfree
(
wdt_mem
);
wdt_mem
=
NULL
;
}
if
(
wdt_irq
!=
NULL
)
{
free_irq
(
wdt_irq
->
start
,
dev
);
wdt_irq
=
NULL
;
}
if
(
wdt_clock
!=
NULL
)
{
clk_disable
(
wdt_clock
);
clk_unuse
(
wdt_clock
);
clk_put
(
wdt_clock
);
wdt_clock
=
NULL
;
}
misc_deregister
(
&
s3c2410wdt_miscdev
);
return
0
;
}
static
struct
device_driver
s3c2410wdt_driver
=
{
.
name
=
"s3c2410-wdt"
,
.
bus
=
&
platform_bus_type
,
.
probe
=
s3c2410wdt_probe
,
.
remove
=
s3c2410wdt_remove
,
};
static
char
banner
[]
__initdata
=
KERN_INFO
"S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
\n
"
;
static
int
__init
watchdog_init
(
void
)
{
printk
(
banner
);
return
driver_register
(
&
s3c2410wdt_driver
);
}
static
void
__exit
watchdog_exit
(
void
)
{
driver_unregister
(
&
s3c2410wdt_driver
);
unregister_reboot_notifier
(
&
s3c2410wdt_notifier
);
}
module_init
(
watchdog_init
);
module_exit
(
watchdog_exit
);
MODULE_AUTHOR
(
"Ben Dooks <ben@simtec.co.uk>"
);
MODULE_DESCRIPTION
(
"S3C2410 Watchdog Device Driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
include/asm-arm/arch-s3c2410/regs-watchdog.h
View file @
4896f66e
...
...
@@ -38,6 +38,7 @@
#define S3C2410_WTCON_DIV128 (3<<3)
#define S3C2410_WTCON_PRESCALE(x) ((x) << 8)
#define S3C2410_WTCON_PRESCALE_MASK (0xff00)
#endif
/* __ASM_ARCH_REGS_WATCHDOG_H */
...
...
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