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
fb33a336
Commit
fb33a336
authored
Feb 27, 2003
by
Dave Jones
Committed by
Dave Jones
Feb 27, 2003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[WATCHDOG] Merge AMD 766/768 TCO Timer/Watchdog driver from 2.4
parent
beaa37ff
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
391 additions
and
0 deletions
+391
-0
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Kconfig
+13
-0
drivers/char/watchdog/Makefile
drivers/char/watchdog/Makefile
+1
-0
drivers/char/watchdog/amd7xx_tco.c
drivers/char/watchdog/amd7xx_tco.c
+377
-0
No files found.
drivers/char/watchdog/Kconfig
View file @
fb33a336
...
...
@@ -313,6 +313,19 @@ config SC520_WDT
You can compile this driver directly into the kernel, or use
it as a module. The module will be called sc520_wdt.
config AMD7XX_TCO
tristate "AMD 766/768 TCO Timer/Watchdog"
depends on WATCHDOG
help
This is the driver for the hardware watchdog built in to the
AMD 766/768 chipsets.
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.
You can compile this driver directly into the kernel, or use
it as a module. The module will be called amd7xx_tco.
config ALIM7101_WDT
tristate "ALi M7101 PMU Computer Watchdog"
depends on WATCHDOG
...
...
drivers/char/watchdog/Makefile
View file @
fb33a336
...
...
@@ -30,3 +30,4 @@ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
obj-$(CONFIG_SC1200_WDT)
+=
sc1200wdt.o
obj-$(CONFIG_WAFER_WDT)
+=
wafer5823wdt.o
obj-$(CONFIG_CPU5_WDT)
+=
cpu5wdt.o
obj-$(CONFIG_AMD7XX_TCO)
+=
amd7xx_tco.o
drivers/char/watchdog/amd7xx_tco.c
0 → 100644
View file @
fb33a336
/*
* AMD 766/768 TCO Timer Driver
* (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
* All Rights Reserved.
*
* Parts from;
* Hardware driver for the AMD 768 Random Number Generator (RNG)
* (c) Copyright 2001 Red Hat Inc <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 version 2
* as published by the Free Software Foundation.
*
* The author(s) of this software shall not be held liable for damages
* of any nature resulting due to the use of this software. This
* software is provided AS-IS with no warranties.
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <linux/ioport.h>
#include <asm/semaphore.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/pci.h>
#define AMDTCO_MODULE_VER "build 20020601"
#define AMDTCO_MODULE_NAME "amd7xx_tco"
#define PFX AMDTCO_MODULE_NAME ": "
#define MAX_TIMEOUT 38
/* max of 38 seconds */
/* pmbase registers */
#define GLOBAL_SMI_REG 0x2a
#define TCO_EN (1 << 1)
/* bit 1 in global SMI register */
#define TCO_RELOAD_REG 0x40
/* bits 0-5 are current count, 6-7 are reserved */
#define TCO_INITVAL_REG 0x41
/* bits 0-5 are value to load, 6-7 are reserved */
#define TCO_TIMEOUT_MASK 0x3f
#define TCO_STATUS2_REG 0x46
#define NDTO_STS2 (1 << 1)
/* we're interested in the second timeout */
#define BOOT_STS (1 << 2)
/* will be set if NDTO_STS2 was set before reboot */
#define TCO_CTRL1_REG 0x48
#define TCO_HALT (1 << 11)
static
char
banner
[]
__initdata
=
KERN_INFO
PFX
AMDTCO_MODULE_VER
;
static
int
timeout
=
38
;
static
u32
pmbase
;
/* PMxx I/O base */
static
struct
pci_dev
*
dev
;
static
struct
semaphore
open_sem
;
spinlock_t
amdtco_lock
;
/* only for device access */
static
int
expect_close
=
0
;
MODULE_PARM
(
timeout
,
"i"
);
MODULE_PARM_DESC
(
timeout
,
"range is 0-38 seconds, default is 38"
);
static
inline
int
amdtco_status
(
void
)
{
u16
reg
;
int
status
=
0
;
reg
=
inb
(
pmbase
+
TCO_CTRL1_REG
);
if
((
reg
&
TCO_HALT
)
==
0
)
status
|=
WDIOF_KEEPALIVEPING
;
reg
=
inb
(
pmbase
+
TCO_STATUS2_REG
);
if
(
reg
&
BOOT_STS
)
status
|=
WDIOF_CARDRESET
;
return
status
;
}
static
inline
void
amdtco_ping
(
void
)
{
u8
reg
;
spin_lock
(
&
amdtco_lock
);
reg
=
inb
(
pmbase
+
TCO_RELOAD_REG
);
outb
(
1
|
reg
,
pmbase
+
TCO_RELOAD_REG
);
spin_unlock
(
&
amdtco_lock
);
}
static
inline
int
amdtco_gettimeout
(
void
)
{
return
inb
(
TCO_RELOAD_REG
)
&
TCO_TIMEOUT_MASK
;
}
static
inline
void
amdtco_settimeout
(
unsigned
int
timeout
)
{
u8
reg
;
spin_lock
(
&
amdtco_lock
);
reg
=
inb
(
pmbase
+
TCO_INITVAL_REG
);
reg
|=
timeout
&
TCO_TIMEOUT_MASK
;
outb
(
reg
,
pmbase
+
TCO_INITVAL_REG
);
spin_unlock
(
&
amdtco_lock
);
}
static
inline
void
amdtco_global_enable
(
void
)
{
u16
reg
;
spin_lock
(
&
amdtco_lock
);
reg
=
inw
(
pmbase
+
GLOBAL_SMI_REG
);
reg
|=
TCO_EN
;
outw
(
reg
,
pmbase
+
GLOBAL_SMI_REG
);
spin_unlock
(
&
amdtco_lock
);
}
static
inline
void
amdtco_enable
(
void
)
{
u16
reg
;
spin_lock
(
&
amdtco_lock
);
reg
=
inw
(
pmbase
+
TCO_CTRL1_REG
);
reg
&=
~
TCO_HALT
;
outw
(
reg
,
pmbase
+
TCO_CTRL1_REG
);
spin_unlock
(
&
amdtco_lock
);
}
static
inline
void
amdtco_disable
(
void
)
{
u16
reg
;
spin_lock
(
&
amdtco_lock
);
reg
=
inw
(
pmbase
+
TCO_CTRL1_REG
);
reg
|=
TCO_HALT
;
outw
(
reg
,
pmbase
+
TCO_CTRL1_REG
);
spin_unlock
(
&
amdtco_lock
);
}
static
int
amdtco_fop_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
down_trylock
(
&
open_sem
))
return
-
EBUSY
;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
MOD_INC_USE_COUNT
;
#endif
if
(
timeout
>
MAX_TIMEOUT
)
timeout
=
MAX_TIMEOUT
;
amdtco_settimeout
(
timeout
);
amdtco_global_enable
();
amdtco_ping
();
printk
(
KERN_INFO
PFX
"Watchdog enabled, timeout = %d/%d seconds"
,
amdtco_gettimeout
(),
timeout
);
return
0
;
}
static
int
amdtco_fop_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
new_timeout
;
int
tmp
;
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_CARDRESET
,
.
identity
=
"AMD 766/768"
};
switch
(
cmd
)
{
default:
return
-
ENOTTY
;
case
WDIOC_GETSUPPORT
:
if
(
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
ident
))
return
-
EFAULT
;
return
0
;
case
WDIOC_GETSTATUS
:
return
put_user
(
amdtco_status
(),
(
int
*
)
arg
);
case
WDIOC_KEEPALIVE
:
amdtco_ping
();
return
0
;
case
WDIOC_SETTIMEOUT
:
if
(
get_user
(
new_timeout
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
(
new_timeout
<
0
)
return
-
EINVAL
;
if
(
new_timeout
>
MAX_TIMEOUT
)
new_timeout
=
MAX_TIMEOUT
;
timeout
=
new_timeout
;
amdtco_settimeout
(
timeout
);
/* fall through and return the new timeout */
case
WDIOC_GETTIMEOUT
:
return
put_user
(
amdtco_gettimeout
(),
(
int
*
)
arg
);
case
WDIOC_SETOPTIONS
:
if
(
copy_from_user
(
&
tmp
,
(
int
*
)
arg
,
sizeof
tmp
))
return
-
EFAULT
;
if
(
tmp
&
WDIOS_DISABLECARD
)
amdtco_disable
();
if
(
tmp
&
WDIOS_ENABLECARD
)
amdtco_enable
();
return
0
;
}
}
static
int
amdtco_fop_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
expect_close
)
{
amdtco_disable
();
printk
(
KERN_INFO
PFX
"Watchdog disabled
\n
"
);
}
else
{
amdtco_ping
();
printk
(
KERN_CRIT
PFX
"Unexpected close!, timeout in %d seconds)
\n
"
,
timeout
);
}
up
(
&
open_sem
);
return
0
;
}
static
ssize_t
amdtco_fop_write
(
struct
file
*
file
,
const
char
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
if
(
len
)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
size_t
i
;
char
c
;
expect_close
=
0
;
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
#endif
amdtco_ping
();
return
len
;
}
return
0
;
}
static
int
amdtco_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
amdtco_disable
();
return
NOTIFY_DONE
;
}
static
struct
notifier_block
amdtco_notifier
=
{
notifier_call:
amdtco_notify_sys
};
static
struct
file_operations
amdtco_fops
=
{
.
owner
=
THIS_MODULE
,
.
write
=
amdtco_fop_write
,
.
ioctl
=
amdtco_fop_ioctl
,
.
open
=
amdtco_fop_open
,
.
release
=
amdtco_fop_release
};
static
struct
miscdevice
amdtco_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
amdtco_fops
};
static
struct
pci_device_id
amdtco_pci_tbl
[]
__initdata
=
{
/* AMD 766 PCI_IDs here */
{
0x1022
,
0x7443
,
PCI_ANY_ID
,
PCI_ANY_ID
,
},
{
0
,
}
};
MODULE_DEVICE_TABLE
(
pci
,
amdtco_pci_tbl
);
static
int
__init
amdtco_init
(
void
)
{
int
ret
;
sema_init
(
&
open_sem
,
1
);
spin_lock_init
(
&
amdtco_lock
);
pci_for_each_dev
(
dev
)
{
if
(
pci_match_device
(
amdtco_pci_tbl
,
dev
)
!=
NULL
)
goto
found_one
;
}
return
-
ENODEV
;
found_one:
if
((
ret
=
register_reboot_notifier
(
&
amdtco_notifier
)))
{
printk
(
KERN_ERR
PFX
"Unable to register reboot notifier err = %d
\n
"
,
ret
);
goto
out_clean
;
}
if
((
ret
=
misc_register
(
&
amdtco_miscdev
)))
{
printk
(
KERN_ERR
PFX
"Unable to register miscdev on minor %d
\n
"
,
WATCHDOG_MINOR
);
goto
out_unreg_reboot
;
}
pci_read_config_dword
(
dev
,
0x58
,
&
pmbase
);
pmbase
&=
0x0000FF00
;
if
(
pmbase
==
0
)
{
printk
(
KERN_ERR
PFX
"power management base not set
\n
"
);
ret
=
-
EIO
;
goto
out_unreg_misc
;
}
/* ret = 0; */
printk
(
banner
);
goto
out_clean
;
out_unreg_misc:
misc_deregister
(
&
amdtco_miscdev
);
out_unreg_reboot:
unregister_reboot_notifier
(
&
amdtco_notifier
);
out_clean:
return
ret
;
}
static
void
__exit
amdtco_exit
(
void
)
{
misc_deregister
(
&
amdtco_miscdev
);
unregister_reboot_notifier
(
&
amdtco_notifier
);
}
#ifndef MODULE
static
int
__init
amdtco_setup
(
char
*
str
)
{
int
ints
[
4
];
str
=
get_options
(
str
,
ARRAY_SIZE
(
ints
),
ints
);
if
(
ints
[
0
]
>
0
)
timeout
=
ints
[
1
];
return
1
;
}
__setup
(
"amd7xx_tco="
,
amdtco_setup
);
#endif
module_init
(
amdtco_init
);
module_exit
(
amdtco_exit
);
MODULE_AUTHOR
(
"Zwane Mwaikambo <zwane@commfireservices.com>"
);
MODULE_DESCRIPTION
(
"AMD 766/768 TCO Timer Driver"
);
MODULE_LICENSE
(
"GPL"
);
EXPORT_NO_SYMBOLS
;
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