Commit 4aa3ba95 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] remove amd7xx_tco

From: Zwane Mwaikambo <zwane@linuxpower.ca>

We've had trouble with this driver, it appears to work but the hardware
never does the final reboot.  I have yet to come across someone with a
board which works and don't have personal access to one.  So how about
scrapping the whole thing.
parent d8d03c0f
......@@ -143,19 +143,6 @@ config ALIM7101_WDT
Most people will say N.
config AMD7XX_TCO
tristate "AMD 766/768 TCO Timer/Watchdog"
depends on WATCHDOG && X86 && PCI
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 SC520_WDT
tristate "AMD Elan SC520 processor Watchdog"
depends on WATCHDOG && X86
......
......@@ -32,7 +32,6 @@ obj-$(CONFIG_ALIM1535_WDT) += alim1535_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
obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
/*
* AMD 766/768 TCO Timer Driver
* (c) Copyright 2002 Zwane Mwaikambo <zwane@holomorphy.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/moduleparam.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/ioport.h>
#include <linux/spinlock.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 20021116"
#define AMDTCO_MODULE_NAME "amd7xx_tco"
#define PFX AMDTCO_MODULE_NAME ": "
#define MAX_TIMEOUT 38 /* max of 38 seconds, although the system will only
* reset itself after the second timeout */
/* pmbase registers */
#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_STATUS1_REG 0x44
#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)
#define NO_REBOOT (1 << 10) /* in DevB:3x48 */
static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER "\n";
static int timeout = MAX_TIMEOUT;
static u32 pmbase; /* PMxx I/O base */
static struct pci_dev *dev;
static struct semaphore open_sem;
static spinlock_t amdtco_lock; /* only for device access */
static char expect_close;
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38");
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static int nowayout = 1;
#else
static int nowayout = 0;
#endif
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
static inline u8 seconds_to_ticks(int seconds)
{
/* the internal timer is stored as ticks which decrement
* every 0.6 seconds */
return (seconds * 10) / 6;
}
static inline int ticks_to_seconds(u8 ticks)
{
return (ticks * 6) / 10;
}
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)
{
outb(1, pmbase+TCO_RELOAD_REG);
}
static inline int amdtco_gettimeout(void)
{
u8 reg = inb(pmbase+TCO_RELOAD_REG) & TCO_TIMEOUT_MASK;
return ticks_to_seconds(reg);
}
static inline void amdtco_settimeout(unsigned int timeout)
{
u8 reg = seconds_to_ticks(timeout) & TCO_TIMEOUT_MASK;
outb(reg, pmbase+TCO_INITVAL_REG);
}
static inline void amdtco_global_enable(void)
{
u16 reg;
spin_lock(&amdtco_lock);
/* clear NO_REBOOT on DevB:3x48 p97 */
pci_read_config_word(dev, 0x48, &reg);
reg &= ~NO_REBOOT;
pci_write_config_word(dev, 0x48, 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;
if (timeout > MAX_TIMEOUT)
timeout = MAX_TIMEOUT;
amdtco_disable();
amdtco_settimeout(timeout);
amdtco_global_enable();
amdtco_enable();
amdtco_ping();
printk(KERN_INFO PFX "Watchdog enabled, timeout = %ds of %ds\n",
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 -ENOIOCTLCMD;
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 == 42) {
amdtco_disable();
printk(KERN_INFO PFX "Watchdog disabled\n");
} else {
amdtco_ping();
printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds\n", timeout);
}
expect_close = 0;
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) {
if (!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 = 42;
}
}
amdtco_ping();
}
return len;
}
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[] = {
/* AMD 766 PCI_IDs here */
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443, 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);
dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
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);
}
module_init(amdtco_init);
module_exit(amdtco_exit);
MODULE_AUTHOR("Zwane Mwaikambo <zwane@holomorphy.com>");
MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment