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
3a3bca5a
Commit
3a3bca5a
authored
Sep 12, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge master.kernel.org:/home/rmk/linux-2.6-arm
parents
bd6fe9e1
b9d36b85
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
444 additions
and
0 deletions
+444
-0
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Kconfig
+9
-0
drivers/char/watchdog/Makefile
drivers/char/watchdog/Makefile
+1
-0
drivers/char/watchdog/mpcore_wdt.c
drivers/char/watchdog/mpcore_wdt.c
+434
-0
No files found.
drivers/char/watchdog/Kconfig
View file @
3a3bca5a
...
...
@@ -139,6 +139,15 @@ config SA1100_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called sa1100_wdt.
config MPCORE_WATCHDOG
tristate "MPcore watchdog"
depends on WATCHDOG && ARM_MPCORE_PLATFORM && LOCAL_TIMERS
help
Watchdog timer embedded into the MPcore system.
To compile this driver as a module, choose M here: the
module will be called mpcore_wdt.
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
...
...
drivers/char/watchdog/Makefile
View file @
3a3bca5a
...
...
@@ -29,6 +29,7 @@ obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
obj-$(CONFIG_IXP4XX_WATCHDOG)
+=
ixp4xx_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG)
+=
s3c2410_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG)
+=
sa1100_wdt.o
obj-$(CONFIG_MPCORE_WATCHDOG)
+=
mpcore_wdt.o
# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT)
+=
acquirewdt.o
...
...
drivers/char/watchdog/mpcore_wdt.c
0 → 100644
View file @
3a3bca5a
/*
* Watchdog driver for the mpcore watchdog timer
*
* (c) Copyright 2004 ARM Limited
*
* Based on the SoftDog driver:
* (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@lxorguk.ukuu.org.uk>
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <asm/uaccess.h>
struct
mpcore_wdt
{
unsigned
long
timer_alive
;
struct
device
*
dev
;
void
__iomem
*
base
;
int
irq
;
unsigned
int
perturb
;
char
expect_close
;
};
static
struct
platform_device
*
mpcore_wdt_dev
;
extern
unsigned
int
mpcore_timer_rate
;
#define TIMER_MARGIN 60
static
int
mpcore_margin
=
TIMER_MARGIN
;
module_param
(
mpcore_margin
,
int
,
0
);
MODULE_PARM_DESC
(
mpcore_margin
,
"MPcore timer margin in seconds. (0<mpcore_margin<65536, default="
__MODULE_STRING
(
TIMER_MARGIN
)
")"
);
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
)
")"
);
#define ONLY_TESTING 0
static
int
mpcore_noboot
=
ONLY_TESTING
;
module_param
(
mpcore_noboot
,
int
,
0
);
MODULE_PARM_DESC
(
mpcore_noboot
,
"MPcore watchdog action, set to 1 to ignore reboots, 0 to reboot (default="
__MODULE_STRING
(
ONLY_TESTING
)
")"
);
/*
* This is the interrupt handler. Note that we only use this
* in testing mode, so don't actually do a reboot here.
*/
static
irqreturn_t
mpcore_wdt_fire
(
int
irq
,
void
*
arg
,
struct
pt_regs
*
regs
)
{
struct
mpcore_wdt
*
wdt
=
arg
;
/* Check it really was our interrupt */
if
(
readl
(
wdt
->
base
+
TWD_WDOG_INTSTAT
))
{
dev_printk
(
KERN_CRIT
,
wdt
->
dev
,
"Triggered - Reboot ignored.
\n
"
);
/* Clear the interrupt on the watchdog */
writel
(
1
,
wdt
->
base
+
TWD_WDOG_INTSTAT
);
return
IRQ_HANDLED
;
}
return
IRQ_NONE
;
}
/*
* mpcore_wdt_keepalive - reload the timer
*
* Note that the spec says a DIFFERENT value must be written to the reload
* register each time. The "perturb" variable deals with this by adding 1
* to the count every other time the function is called.
*/
static
void
mpcore_wdt_keepalive
(
struct
mpcore_wdt
*
wdt
)
{
unsigned
int
count
;
/* Assume prescale is set to 256 */
count
=
(
mpcore_timer_rate
/
256
)
*
mpcore_margin
;
/* Reload the counter */
writel
(
count
+
wdt
->
perturb
,
wdt
->
base
+
TWD_WDOG_LOAD
);
wdt
->
perturb
=
wdt
->
perturb
?
0
:
1
;
}
static
void
mpcore_wdt_stop
(
struct
mpcore_wdt
*
wdt
)
{
writel
(
0x12345678
,
wdt
->
base
+
TWD_WDOG_DISABLE
);
writel
(
0x87654321
,
wdt
->
base
+
TWD_WDOG_DISABLE
);
writel
(
0x0
,
wdt
->
base
+
TWD_WDOG_CONTROL
);
}
static
void
mpcore_wdt_start
(
struct
mpcore_wdt
*
wdt
)
{
dev_printk
(
KERN_INFO
,
wdt
->
dev
,
"enabling watchdog.
\n
"
);
/* This loads the count register but does NOT start the count yet */
mpcore_wdt_keepalive
(
wdt
);
if
(
mpcore_noboot
)
{
/* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */
writel
(
0x0000FF01
,
wdt
->
base
+
TWD_WDOG_CONTROL
);
}
else
{
/* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
writel
(
0x0000FF09
,
wdt
->
base
+
TWD_WDOG_CONTROL
);
}
}
static
int
mpcore_wdt_set_heartbeat
(
int
t
)
{
if
(
t
<
0x0001
||
t
>
0xFFFF
)
return
-
EINVAL
;
mpcore_margin
=
t
;
return
0
;
}
/*
* /dev/watchdog handling
*/
static
int
mpcore_wdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
mpcore_wdt
*
wdt
=
dev_get_drvdata
(
&
mpcore_wdt_dev
->
dev
);
if
(
test_and_set_bit
(
0
,
&
wdt
->
timer_alive
))
return
-
EBUSY
;
if
(
nowayout
)
__module_get
(
THIS_MODULE
);
file
->
private_data
=
wdt
;
/*
* Activate timer
*/
mpcore_wdt_start
(
wdt
);
return
nonseekable_open
(
inode
,
file
);
}
static
int
mpcore_wdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
mpcore_wdt
*
wdt
=
file
->
private_data
;
/*
* Shut off the timer.
* Lock it in if it's a module and we set nowayout
*/
if
(
wdt
->
expect_close
==
42
)
{
mpcore_wdt_stop
(
wdt
);
}
else
{
dev_printk
(
KERN_CRIT
,
wdt
->
dev
,
"unexpected close, not stopping watchdog!
\n
"
);
mpcore_wdt_keepalive
(
wdt
);
}
clear_bit
(
0
,
&
wdt
->
timer_alive
);
wdt
->
expect_close
=
0
;
return
0
;
}
static
ssize_t
mpcore_wdt_write
(
struct
file
*
file
,
const
char
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
struct
mpcore_wdt
*
wdt
=
file
->
private_data
;
/* Can't seek (pwrite) on this device */
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
/*
* Refresh the timer.
*/
if
(
len
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
wdt
->
expect_close
=
0
;
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
wdt
->
expect_close
=
42
;
}
}
mpcore_wdt_keepalive
(
wdt
);
}
return
len
;
}
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
identity
=
"MPcore Watchdog"
,
};
static
int
mpcore_wdt_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
mpcore_wdt
*
wdt
=
file
->
private_data
;
int
ret
;
union
{
struct
watchdog_info
ident
;
int
i
;
}
uarg
;
if
(
_IOC_DIR
(
cmd
)
&&
_IOC_SIZE
(
cmd
)
>
sizeof
(
uarg
))
return
-
ENOIOCTLCMD
;
if
(
_IOC_DIR
(
cmd
)
&
_IOC_WRITE
)
{
ret
=
copy_from_user
(
&
uarg
,
(
void
__user
*
)
arg
,
_IOC_SIZE
(
cmd
));
if
(
ret
)
return
-
EFAULT
;
}
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
uarg
.
ident
=
ident
;
ret
=
0
;
break
;
case
WDIOC_SETOPTIONS
:
ret
=
-
EINVAL
;
if
(
uarg
.
i
&
WDIOS_DISABLECARD
)
{
mpcore_wdt_stop
(
wdt
);
ret
=
0
;
}
if
(
uarg
.
i
&
WDIOS_ENABLECARD
)
{
mpcore_wdt_start
(
wdt
);
ret
=
0
;
}
break
;
case
WDIOC_GETSTATUS
:
case
WDIOC_GETBOOTSTATUS
:
uarg
.
i
=
0
;
ret
=
0
;
break
;
case
WDIOC_KEEPALIVE
:
mpcore_wdt_keepalive
(
wdt
);
ret
=
0
;
break
;
case
WDIOC_SETTIMEOUT
:
ret
=
mpcore_wdt_set_heartbeat
(
uarg
.
i
);
if
(
ret
)
break
;
mpcore_wdt_keepalive
(
wdt
);
/* Fall */
case
WDIOC_GETTIMEOUT
:
uarg
.
i
=
mpcore_margin
;
ret
=
0
;
break
;
default:
return
-
ENOIOCTLCMD
;
}
if
(
ret
==
0
&&
_IOC_DIR
(
cmd
)
&
_IOC_READ
)
{
ret
=
copy_to_user
((
void
__user
*
)
arg
,
&
uarg
,
_IOC_SIZE
(
cmd
));
if
(
ret
)
ret
=
-
EFAULT
;
}
return
ret
;
}
/*
* System shutdown handler. Turn off the watchdog if we're
* restarting or halting the system.
*/
static
void
mpcore_wdt_shutdown
(
struct
device
*
_dev
)
{
struct
mpcore_wdt
*
wdt
=
dev_get_drvdata
(
_dev
);
if
(
system_state
==
SYSTEM_RESTART
||
system_state
==
SYSTEM_HALT
)
mpcore_wdt_stop
(
wdt
);
}
/*
* Kernel Interfaces
*/
static
struct
file_operations
mpcore_wdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
mpcore_wdt_write
,
.
ioctl
=
mpcore_wdt_ioctl
,
.
open
=
mpcore_wdt_open
,
.
release
=
mpcore_wdt_release
,
};
static
struct
miscdevice
mpcore_wdt_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
mpcore_wdt_fops
,
};
static
int
__devinit
mpcore_wdt_probe
(
struct
device
*
_dev
)
{
struct
platform_device
*
dev
=
to_platform_device
(
_dev
);
struct
mpcore_wdt
*
wdt
;
struct
resource
*
res
;
int
ret
;
/* We only accept one device, and it must have an id of -1 */
if
(
dev
->
id
!=
-
1
)
return
-
ENODEV
;
res
=
platform_get_resource
(
dev
,
IORESOURCE_MEM
,
0
);
if
(
!
res
)
{
ret
=
-
ENODEV
;
goto
err_out
;
}
wdt
=
kmalloc
(
sizeof
(
struct
mpcore_wdt
),
GFP_KERNEL
);
if
(
!
wdt
)
{
ret
=
-
ENOMEM
;
goto
err_out
;
}
memset
(
wdt
,
0
,
sizeof
(
struct
mpcore_wdt
));
wdt
->
dev
=
&
dev
->
dev
;
wdt
->
irq
=
platform_get_irq
(
dev
,
0
);
wdt
->
base
=
ioremap
(
res
->
start
,
res
->
end
-
res
->
start
+
1
);
if
(
!
wdt
->
base
)
{
ret
=
-
ENOMEM
;
goto
err_free
;
}
mpcore_wdt_miscdev
.
dev
=
&
dev
->
dev
;
ret
=
misc_register
(
&
mpcore_wdt_miscdev
);
if
(
ret
)
{
dev_printk
(
KERN_ERR
,
_dev
,
"cannot register miscdev on minor=%d (err=%d)
\n
"
,
WATCHDOG_MINOR
,
ret
);
goto
err_misc
;
}
ret
=
request_irq
(
wdt
->
irq
,
mpcore_wdt_fire
,
SA_INTERRUPT
,
"mpcore_wdt"
,
wdt
);
if
(
ret
)
{
dev_printk
(
KERN_ERR
,
_dev
,
"cannot register IRQ%d for watchdog
\n
"
,
wdt
->
irq
);
goto
err_irq
;
}
mpcore_wdt_stop
(
wdt
);
dev_set_drvdata
(
&
dev
->
dev
,
wdt
);
mpcore_wdt_dev
=
dev
;
return
0
;
err_irq:
misc_deregister
(
&
mpcore_wdt_miscdev
);
err_misc:
iounmap
(
wdt
->
base
);
err_free:
kfree
(
wdt
);
err_out:
return
ret
;
}
static
int
__devexit
mpcore_wdt_remove
(
struct
device
*
dev
)
{
struct
mpcore_wdt
*
wdt
=
dev_get_drvdata
(
dev
);
dev_set_drvdata
(
dev
,
NULL
);
misc_deregister
(
&
mpcore_wdt_miscdev
);
mpcore_wdt_dev
=
NULL
;
free_irq
(
wdt
->
irq
,
wdt
);
iounmap
(
wdt
->
base
);
kfree
(
wdt
);
return
0
;
}
static
struct
device_driver
mpcore_wdt_driver
=
{
.
name
=
"mpcore_wdt"
,
.
bus
=
&
platform_bus_type
,
.
probe
=
mpcore_wdt_probe
,
.
remove
=
__devexit_p
(
mpcore_wdt_remove
),
.
shutdown
=
mpcore_wdt_shutdown
,
};
static
char
banner
[]
__initdata
=
KERN_INFO
"MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)
\n
"
;
static
int
__init
mpcore_wdt_init
(
void
)
{
/*
* Check that the margin value is within it's range;
* if not reset to the default
*/
if
(
mpcore_wdt_set_heartbeat
(
mpcore_margin
))
{
mpcore_wdt_set_heartbeat
(
TIMER_MARGIN
);
printk
(
KERN_INFO
"mpcore_margin value must be 0<mpcore_margin<65536, using %d
\n
"
,
TIMER_MARGIN
);
}
printk
(
banner
,
mpcore_noboot
,
mpcore_margin
,
nowayout
);
return
driver_register
(
&
mpcore_wdt_driver
);
}
static
void
__exit
mpcore_wdt_exit
(
void
)
{
driver_unregister
(
&
mpcore_wdt_driver
);
}
module_init
(
mpcore_wdt_init
);
module_exit
(
mpcore_wdt_exit
);
MODULE_AUTHOR
(
"ARM Limited"
);
MODULE_DESCRIPTION
(
"MPcore Watchdog Device Driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
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