X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fwatchdog%2Fi8xx_tco.c;h=fa2ba9ebe42aacf3478212143547c460d877402e;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=efe3c1d9eb95596dab021bfeb112bcea841fd539;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index efe3c1d9e..fa2ba9ebe 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c @@ -1,5 +1,5 @@ /* - * i8xx_tco 0.06: TCO timer driver for i8xx chipsets + * i8xx_tco: TCO timer driver for i8xx chipsets * * (c) Copyright 2000 kernel concepts , All Rights Reserved. * http://www.kernelconcepts.de @@ -22,11 +22,17 @@ * * The TCO timer is implemented in the following I/O controller hubs: * (See the intel documentation on http://developer.intel.com.) - * 82801AA & 82801AB chip : document number 290655-003, 290677-004, - * 82801BA & 82801BAM chip : document number 290687-002, 298242-005, - * 82801CA & 82801CAM chip : document number 290716-001, 290718-001, - * 82801DB & 82801E chip : document number 290744-001, 273599-001, - * 82801EB & 82801ER chip : document number 252516-001 + * 82801AA (ICH) : document number 290655-003, 290677-014, + * 82801AB (ICHO) : document number 290655-003, 290677-014, + * 82801BA (ICH2) : document number 290687-002, 298242-027, + * 82801BAM (ICH2-M) : document number 290687-002, 298242-027, + * 82801CA (ICH3-S) : document number 290733-003, 290739-013, + * 82801CAM (ICH3-M) : document number 290716-001, 290718-007, + * 82801DB (ICH4) : document number 290744-001, 290745-020, + * 82801DBM (ICH4-M) : document number 252337-001, 252663-005, + * 82801E (C-ICH) : document number 273599-001, 273645-002, + * 82801EB (ICH5) : document number 252516-001, 252517-003, + * 82801ER (ICH5R) : document number 252516-001, 252517-003, * * 20000710 Nils Faerber * Initial Version 0.01 @@ -49,6 +55,16 @@ * 20030921 Wim Van Sebroeck * 0.06 change i810_margin to heartbeat, use module_param, * added notify system support, renamed module to i8xx_tco. + * 20050128 Wim Van Sebroeck + * 0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW + * chipsets. Also added support for the "undocumented" ICH7 chipset. + * 20050807 Wim Van Sebroeck + * 0.08 Make sure that the watchdog is only "armed" when started. + * (Kernel Bug 4251) + * 20060416 Wim Van Sebroeck + * 0.09 Remove support for the ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW and + * ICH7 chipsets. (See Kernel Bug 6031 - other code will support these + * chipsets) */ /* @@ -73,7 +89,7 @@ #include "i8xx_tco.h" /* Module and version information */ -#define TCO_VERSION "0.06" +#define TCO_VERSION "0.09" #define TCO_MODULE_NAME "i8xx TCO timer" #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION #define PFX TCO_MODULE_NAME ": " @@ -91,12 +107,7 @@ static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ module_param(heartbeat, int, 0); MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2 0 = The TCO timer is enabled to count */ val = inb (TCO1_CNT + 1); val &= 0xf7; outb (val, TCO1_CNT + 1); val = inb (TCO1_CNT + 1); + spin_unlock(&tco_lock); if (val & 0x08) @@ -129,13 +148,20 @@ static int tco_timer_start (void) static int tco_timer_stop (void) { - unsigned char val; + unsigned char val, val1; spin_lock(&tco_lock); + /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ val = inb (TCO1_CNT + 1); val |= 0x08; outb (val, TCO1_CNT + 1); val = inb (TCO1_CNT + 1); + + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); + val1 |= 0x02; + pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); + spin_unlock(&tco_lock); if ((val & 0x08) == 0) @@ -146,6 +172,7 @@ static int tco_timer_stop (void) static int tco_timer_keepalive (void) { spin_lock(&tco_lock); + /* Reload the timer by writing to the TCO Timer Reload register */ outb (0x01, TCO1_RLD); spin_unlock(&tco_lock); return 0; @@ -193,7 +220,7 @@ static int i8xx_tco_open (struct inode *inode, struct file *file) */ tco_timer_keepalive (); tco_timer_start (); - return 0; + return nonseekable_open(inode, file); } static int i8xx_tco_release (struct inode *inode, struct file *file) @@ -212,13 +239,9 @@ static int i8xx_tco_release (struct inode *inode, struct file *file) return 0; } -static ssize_t i8xx_tco_write (struct file *file, const char *data, +static ssize_t i8xx_tco_write (struct file *file, const char __user *data, size_t len, loff_t * ppos) { - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - /* See if we got the magic character 'V' and reload the timer */ if (len) { if (!nowayout) { @@ -249,6 +272,8 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file, { int new_options, retval = -EINVAL; int new_heartbeat; + void __user *argp = (void __user *)arg; + int __user *p = argp; static struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | @@ -259,12 +284,12 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file, switch (cmd) { case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *) arg, &ident, + return copy_to_user(argp, &ident, sizeof (ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: - return put_user (0, (int *) arg); + return put_user (0, p); case WDIOC_KEEPALIVE: tco_timer_keepalive (); @@ -272,7 +297,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file, case WDIOC_SETOPTIONS: { - if (get_user (new_options, (int *) arg)) + if (get_user (new_options, p)) return -EFAULT; if (new_options & WDIOS_DISABLECARD) { @@ -291,7 +316,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file, case WDIOC_SETTIMEOUT: { - if (get_user(new_heartbeat, (int *) arg)) + if (get_user(new_heartbeat, p)) return -EFAULT; if (tco_timer_set_heartbeat(new_heartbeat)) @@ -302,7 +327,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file, } case WDIOC_GETTIMEOUT: - return put_user(heartbeat, (int *)arg); + return put_user(heartbeat, p); default: return -ENOIOCTLCMD; @@ -362,8 +387,10 @@ static struct pci_device_id i8xx_tco_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl); @@ -382,7 +409,7 @@ static unsigned char __init i8xx_tco_getdevice (void) */ while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (pci_match_device(i8xx_tco_pci_tbl, dev)) { + if (pci_match_id(i8xx_tco_pci_tbl, dev)) { i8xx_tco_pci = dev; break; } @@ -403,9 +430,8 @@ static unsigned char __init i8xx_tco_getdevice (void) printk (KERN_ERR PFX "failed to get TCOBASE address\n"); return 0; } - /* - * Check chipset's NO_REBOOT bit - */ + + /* Check chipset's NO_REBOOT bit */ pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); if (val1 & 0x02) { val1 &= 0xfd; @@ -416,13 +442,20 @@ static unsigned char __init i8xx_tco_getdevice (void) return 0; /* Cannot reset NO_REBOOT bit */ } } + /* Disable reboots untill the watchdog starts */ + val1 |= 0x02; + pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); + /* Set the TCO_EN bit in SMI_EN register */ + if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) { + printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", + SMI_EN + 1); + return 0; + } val1 = inb (SMI_EN + 1); val1 &= 0xdf; outb (val1, SMI_EN + 1); - /* Clear out the (probably old) status */ - outb (0, TCO1_STS); - outb (3, TCO2_STS); + release_region (SMI_EN + 1, 1); return 1; } return 0; @@ -445,6 +478,10 @@ static int __init watchdog_init (void) goto out; } + /* Clear out the (probably old) status */ + outb (0, TCO1_STS); + outb (3, TCO2_STS); + /* Check that the heartbeat value is within it's range ; if not reset to the default */ if (tco_timer_set_heartbeat (heartbeat)) { heartbeat = WATCHDOG_HEARTBEAT; @@ -467,7 +504,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); @@ -484,17 +521,10 @@ out: static void __exit watchdog_cleanup (void) { - u8 val; - /* Stop the timer before we leave */ if (!nowayout) tco_timer_stop (); - /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - pci_read_config_byte (i8xx_tco_pci, 0xd4, &val); - val |= 0x02; - pci_write_config_byte (i8xx_tco_pci, 0xd4, val); - /* Deregister */ misc_deregister (&i8xx_tco_miscdev); unregister_reboot_notifier(&i8xx_tco_notifier);