diff options
Diffstat (limited to 'drivers/watchdog/iTCO_wdt.c')
-rw-r--r-- | drivers/watchdog/iTCO_wdt.c | 71 |
1 files changed, 49 insertions, 22 deletions
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 8da886035374..2c6c2b4ad8bf 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -1,7 +1,7 @@ /* * intel TCO Watchdog Driver * - * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>. + * (c) Copyright 2006-2010 Wim Van Sebroeck <wim@iguana.be>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,12 +26,15 @@ * document number 301473-002, 301474-026: 82801F (ICH6) * document number 313082-001, 313075-006: 631xESB, 632xESB * document number 307013-003, 307014-024: 82801G (ICH7) + * document number 322896-001, 322897-001: NM10 * document number 313056-003, 313057-017: 82801H (ICH8) * document number 316972-004, 316973-012: 82801I (ICH9) * document number 319973-002, 319974-002: 82801J (ICH10) * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) * document number 320066-003, 320257-008: EP80597 (IICH) - * document number TBD : Cougar Point (CPT) + * document number 324645-001, 324646-001: Cougar Point (CPT) + * document number TBD : Patsburg (PBG) + * document number TBD : DH89xxCC */ /* @@ -40,7 +43,7 @@ /* Module and version information */ #define DRV_NAME "iTCO_wdt" -#define DRV_VERSION "1.05" +#define DRV_VERSION "1.06" #define PFX DRV_NAME ": " /* Includes */ @@ -84,6 +87,7 @@ enum iTCO_chipsets { TCO_ICH7DH, /* ICH7DH */ TCO_ICH7M, /* ICH7-M & ICH7-U */ TCO_ICH7MDH, /* ICH7-M DH */ + TCO_NM10, /* NM10 */ TCO_ICH8, /* ICH8 & ICH8R */ TCO_ICH8DH, /* ICH8DH */ TCO_ICH8DO, /* ICH8DO */ @@ -146,6 +150,9 @@ enum iTCO_chipsets { TCO_CPT29, /* Cougar Point */ TCO_CPT30, /* Cougar Point */ TCO_CPT31, /* Cougar Point */ + TCO_PBG1, /* Patsburg */ + TCO_PBG2, /* Patsburg */ + TCO_DH89XXCC, /* DH89xxCC */ }; static struct { @@ -171,6 +178,7 @@ static struct { {"ICH7DH", 2}, {"ICH7-M or ICH7-U", 2}, {"ICH7-M DH", 2}, + {"NM10", 2}, {"ICH8 or ICH8R", 2}, {"ICH8DH", 2}, {"ICH8DO", 2}, @@ -233,6 +241,9 @@ static struct { {"Cougar Point", 2}, {"Cougar Point", 2}, {"Cougar Point", 2}, + {"Patsburg", 2}, + {"Patsburg", 2}, + {"DH89xxCC", 2}, {NULL, 0} }; @@ -286,6 +297,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)}, + { ITCO_PCI_DEVICE(0x27bc, TCO_NM10)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)}, @@ -348,6 +360,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { ITCO_PCI_DEVICE(0x1c5d, TCO_CPT29)}, { ITCO_PCI_DEVICE(0x1c5e, TCO_CPT30)}, { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)}, + { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)}, + { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)}, + { ITCO_PCI_DEVICE(0x2310, TCO_DH89XXCC)}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); @@ -374,7 +389,7 @@ static char expect_release; static struct { /* this is private data for the iTCO_wdt device */ /* TCO version/generation */ unsigned int iTCO_version; - /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ + /* The device's ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ unsigned long ACPIBASE; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/ unsigned long __iomem *gcs; @@ -391,8 +406,8 @@ static struct platform_device *iTCO_wdt_platform_device; #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ module_param(heartbeat, int, 0); -MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. " - "(2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=" +MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. " + "5..76 (TCO v1) or 3..614 (TCO v2), default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); static int nowayout = WATCHDOG_NOWAYOUT; @@ -467,7 +482,7 @@ static int iTCO_wdt_start(void) if (iTCO_wdt_unset_NO_REBOOT_bit()) { spin_unlock(&iTCO_wdt_private.io_lock); printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, " - "reboot disabled by hardware\n"); + "reboot disabled by hardware/BIOS\n"); return -EIO; } @@ -523,8 +538,13 @@ static int iTCO_wdt_keepalive(void) /* Reload the timer by writing to the TCO Timer Counter register */ if (iTCO_wdt_private.iTCO_version == 2) outw(0x01, TCO_RLD); - else if (iTCO_wdt_private.iTCO_version == 1) + else if (iTCO_wdt_private.iTCO_version == 1) { + /* Reset the timeout status bit so that the timer + * needs to count down twice again before rebooting */ + outw(0x0008, TCO1_STS); /* write 1 to clear bit */ + outb(0x01, TCO_RLD); + } spin_unlock(&iTCO_wdt_private.io_lock); return 0; @@ -537,6 +557,11 @@ static int iTCO_wdt_set_heartbeat(int t) unsigned int tmrval; tmrval = seconds_to_ticks(t); + + /* For TCO v1 the timer counts down twice before rebooting */ + if (iTCO_wdt_private.iTCO_version == 1) + tmrval /= 2; + /* from the specs: */ /* "Values of 0h-3h are ignored and should not be attempted" */ if (tmrval < 0x04) @@ -593,6 +618,8 @@ static int iTCO_wdt_get_timeleft(int *time_left) spin_lock(&iTCO_wdt_private.io_lock); val8 = inb(TCO_RLD); val8 &= 0x3f; + if (!(inw(TCO1_STS) & 0x0008)) + val8 += (inb(TCOv1_TMR) & 0x3f); spin_unlock(&iTCO_wdt_private.io_lock); *time_left = (val8 * 6) / 10; @@ -769,8 +796,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, base_address &= 0x0000ff80; if (base_address == 0x00000000) { /* Something's wrong here, ACPIBASE has to be set */ - printk(KERN_ERR PFX "failed to get TCOBASE address\n"); - pci_dev_put(pdev); + printk(KERN_ERR PFX "failed to get TCOBASE address, " + "device disabled by hardware/BIOS\n"); return -ENODEV; } iTCO_wdt_private.iTCO_version = @@ -785,7 +812,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, if (iTCO_wdt_private.iTCO_version == 2) { pci_read_config_dword(pdev, 0xf0, &base_address); if ((base_address & 1) == 0) { - printk(KERN_ERR PFX "RCBA is disabled by hardware\n"); + printk(KERN_ERR PFX "RCBA is disabled by hardware" + "/BIOS, device disabled\n"); ret = -ENODEV; goto out; } @@ -796,7 +824,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, /* Check chipset's NO_REBOOT bit */ if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, " - "platform may have disabled it\n"); + "device disabled by hardware/BIOS\n"); ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ goto out_unmap; } @@ -807,7 +835,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ if (!request_region(SMI_EN, 4, "iTCO_wdt")) { printk(KERN_ERR PFX - "I/O address 0x%04lx already in use\n", SMI_EN); + "I/O address 0x%04lx already in use, " + "device disabled\n", SMI_EN); ret = -EIO; goto out_unmap; } @@ -819,8 +848,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */ if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) { - printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", - TCOBASE); + printk(KERN_ERR PFX "I/O address 0x%04lx already in use " + "device disabled\n", TCOBASE); ret = -EIO; goto unreg_smi_en; } @@ -832,9 +861,9 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, TCOBASE); /* Clear out the (probably old) status */ - outb(8, TCO1_STS); /* Clear the Time Out Status bit */ - outb(2, TCO2_STS); /* Clear SECOND_TO_STS bit */ - outb(4, TCO2_STS); /* Clear BOOT_STS bit */ + outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */ + outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */ + outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */ /* Make sure the watchdog is not running */ iTCO_wdt_stop(); @@ -844,8 +873,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, if (iTCO_wdt_set_heartbeat(heartbeat)) { iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT); printk(KERN_INFO PFX - "heartbeat value must be 2 < heartbeat < 39 (TCO v1) " - "or 613 (TCO v2), using %d\n", heartbeat); + "timeout value out of range, using %d\n", heartbeat); } ret = misc_register(&iTCO_wdt_miscdev); @@ -869,7 +897,6 @@ out_unmap: if (iTCO_wdt_private.iTCO_version == 2) iounmap(iTCO_wdt_private.gcs); out: - pci_dev_put(iTCO_wdt_private.pdev); iTCO_wdt_private.ACPIBASE = 0; return ret; } @@ -910,7 +937,7 @@ static int __devinit iTCO_wdt_probe(struct platform_device *dev) } if (!found) - printk(KERN_INFO PFX "No card detected\n"); + printk(KERN_INFO PFX "No device detected.\n"); return ret; } |