Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
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
...
@@ -139,6 +139,15 @@ config SA1100_WATCHDOG
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 sa1100_wdt.
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
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
config ACQUIRE_WDT
...
...
drivers/char/watchdog/Makefile
View file @
3a3bca5a
...
@@ -29,6 +29,7 @@ obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
...
@@ -29,6 +29,7 @@ obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
obj-$(CONFIG_IXP4XX_WATCHDOG)
+=
ixp4xx_wdt.o
obj-$(CONFIG_IXP4XX_WATCHDOG)
+=
ixp4xx_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG)
+=
s3c2410_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG)
+=
s3c2410_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG)
+=
sa1100_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG)
+=
sa1100_wdt.o
obj-$(CONFIG_MPCORE_WATCHDOG)
+=
mpcore_wdt.o
# X86 (i386 + ia64 + x86_64) Architecture
# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT)
+=
acquirewdt.o
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