Merge master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog

* master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
[WATCHDOG] iTCO_wdt.c shutdown patch
[WATCHDOG] iTCO_wdt.c - pci_dev_put fix
[WATCHDOG] iTCO_wdt (Intel TCO Timer) driver
[WATCHDOG] iTCO_wdt (Intel TCO Timer) driver

+757
+21
drivers/char/watchdog/Kconfig
··· 316 316 To compile this driver as a module, choose M here: the 317 317 module will be called i8xx_tco. 318 318 319 + config ITCO_WDT 320 + tristate "Intel TCO Timer/Watchdog (EXPERIMENTAL)" 321 + depends on WATCHDOG && (X86 || IA64) && PCI && EXPERIMENTAL 322 + ---help--- 323 + Hardware driver for the intel TCO timer based watchdog devices. 324 + These drivers are included in the Intel 82801 I/O Controller 325 + Hub family 'from ICH0 up to ICH7) and in the Intel 6300ESB 326 + controller hub. 327 + 328 + The TCO (Total Cost of Ownership) timer is a watchdog timer 329 + that will reboot the machine after its second expiration. The 330 + expiration time can be configured with the "heartbeat" parameter. 331 + 332 + On some motherboards the driver may fail to reset the chipset's 333 + NO_REBOOT flag which prevents the watchdog from rebooting the 334 + machine. If this is the case you will get a kernel message like 335 + "failed to reset NO_REBOOT flag, reboot disabled by hardware". 336 + 337 + To compile this driver as a module, choose M here: the 338 + module will be called iTCO_wdt. 339 + 319 340 config SC1200_WDT 320 341 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" 321 342 depends on WATCHDOG && X86
+1
drivers/char/watchdog/Makefile
··· 47 47 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o 48 48 obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o 49 49 obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o 50 + obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o 50 51 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o 51 52 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o 52 53 obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
+735
drivers/char/watchdog/iTCO_wdt.c
··· 1 + /* 2 + * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets) 3 + * 4 + * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>. 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + * 11 + * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor 12 + * provide warranty for any of this software. This material is 13 + * provided "AS-IS" and at no charge. 14 + * 15 + * The TCO watchdog is implemented in the following I/O controller hubs: 16 + * (See the intel documentation on http://developer.intel.com.) 17 + * 82801AA (ICH) : document number 290655-003, 290677-014, 18 + * 82801AB (ICHO) : document number 290655-003, 290677-014, 19 + * 82801BA (ICH2) : document number 290687-002, 298242-027, 20 + * 82801BAM (ICH2-M) : document number 290687-002, 298242-027, 21 + * 82801CA (ICH3-S) : document number 290733-003, 290739-013, 22 + * 82801CAM (ICH3-M) : document number 290716-001, 290718-007, 23 + * 82801DB (ICH4) : document number 290744-001, 290745-020, 24 + * 82801DBM (ICH4-M) : document number 252337-001, 252663-005, 25 + * 82801E (C-ICH) : document number 273599-001, 273645-002, 26 + * 82801EB (ICH5) : document number 252516-001, 252517-003, 27 + * 82801ER (ICH5R) : document number 252516-001, 252517-003, 28 + * 82801FB (ICH6) : document number 301473-002, 301474-007, 29 + * 82801FR (ICH6R) : document number 301473-002, 301474-007, 30 + * 82801FBM (ICH6-M) : document number 301473-002, 301474-007, 31 + * 82801FW (ICH6W) : document number 301473-001, 301474-007, 32 + * 82801FRW (ICH6RW) : document number 301473-001, 301474-007, 33 + * 82801GB (ICH7) : document number 307013-002, 307014-009, 34 + * 82801GR (ICH7R) : document number 307013-002, 307014-009, 35 + * 82801GDH (ICH7DH) : document number 307013-002, 307014-009, 36 + * 82801GBM (ICH7-M) : document number 307013-002, 307014-009, 37 + * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, 38 + * 6300ESB (6300ESB) : document number 300641-003 39 + */ 40 + 41 + /* 42 + * Includes, defines, variables, module parameters, ... 43 + */ 44 + 45 + /* Module and version information */ 46 + #define DRV_NAME "iTCO_wdt" 47 + #define DRV_VERSION "1.00" 48 + #define DRV_RELDATE "30-Jul-2006" 49 + #define PFX DRV_NAME ": " 50 + 51 + /* Includes */ 52 + #include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */ 53 + #include <linux/module.h> /* For module specific items */ 54 + #include <linux/moduleparam.h> /* For new moduleparam's */ 55 + #include <linux/types.h> /* For standard types (like size_t) */ 56 + #include <linux/errno.h> /* For the -ENODEV/... values */ 57 + #include <linux/kernel.h> /* For printk/panic/... */ 58 + #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ 59 + #include <linux/watchdog.h> /* For the watchdog specific items */ 60 + #include <linux/init.h> /* For __init/__exit/... */ 61 + #include <linux/fs.h> /* For file operations */ 62 + #include <linux/platform_device.h> /* For platform_driver framework */ 63 + #include <linux/pci.h> /* For pci functions */ 64 + #include <linux/ioport.h> /* For io-port access */ 65 + #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ 66 + 67 + #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ 68 + #include <asm/io.h> /* For inb/outb/... */ 69 + 70 + /* TCO related info */ 71 + enum iTCO_chipsets { 72 + TCO_ICH = 0, /* ICH */ 73 + TCO_ICH0, /* ICH0 */ 74 + TCO_ICH2, /* ICH2 */ 75 + TCO_ICH2M, /* ICH2-M */ 76 + TCO_ICH3, /* ICH3-S */ 77 + TCO_ICH3M, /* ICH3-M */ 78 + TCO_ICH4, /* ICH4 */ 79 + TCO_ICH4M, /* ICH4-M */ 80 + TCO_CICH, /* C-ICH */ 81 + TCO_ICH5, /* ICH5 & ICH5R */ 82 + TCO_6300ESB, /* 6300ESB */ 83 + TCO_ICH6, /* ICH6 & ICH6R */ 84 + TCO_ICH6M, /* ICH6-M */ 85 + TCO_ICH6W, /* ICH6W & ICH6RW */ 86 + TCO_ICH7, /* ICH7 & ICH7R */ 87 + TCO_ICH7M, /* ICH7-M */ 88 + TCO_ICH7MDH, /* ICH7-M DH */ 89 + }; 90 + 91 + static struct { 92 + char *name; 93 + unsigned int iTCO_version; 94 + } iTCO_chipset_info[] __devinitdata = { 95 + {"ICH", 1}, 96 + {"ICH0", 1}, 97 + {"ICH2", 1}, 98 + {"ICH2-M", 1}, 99 + {"ICH3-S", 1}, 100 + {"ICH3-M", 1}, 101 + {"ICH4", 1}, 102 + {"ICH4-M", 1}, 103 + {"C-ICH", 1}, 104 + {"ICH5 or ICH5R", 1}, 105 + {"6300ESB", 1}, 106 + {"ICH6 or ICH6R", 2}, 107 + {"ICH6-M", 2}, 108 + {"ICH6W or ICH6RW", 2}, 109 + {"ICH7 or ICH7R", 2}, 110 + {"ICH7-M", 2}, 111 + {"ICH7-M DH", 2}, 112 + {NULL,0} 113 + }; 114 + 115 + /* 116 + * This data only exists for exporting the supported PCI ids 117 + * via MODULE_DEVICE_TABLE. We do not actually register a 118 + * pci_driver, because the I/O Controller Hub has also other 119 + * functions that probably will be registered by other drivers. 120 + */ 121 + static struct pci_device_id iTCO_wdt_pci_tbl[] = { 122 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH }, 123 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH0 }, 124 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2 }, 125 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2M }, 126 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3 }, 127 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3M }, 128 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4 }, 129 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4M }, 130 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_CICH }, 131 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH5 }, 132 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_6300ESB }, 133 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6 }, 134 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6M }, 135 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6W }, 136 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, 137 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, 138 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, 139 + { 0, }, /* End of list */ 140 + }; 141 + MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); 142 + 143 + /* Address definitions for the TCO */ 144 + #define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 /* TCO base address */ 145 + #define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 /* SMI Control and Enable Register */ 146 + 147 + #define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */ 148 + #define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */ 149 + #define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ 150 + #define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ 151 + #define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ 152 + #define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */ 153 + #define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */ 154 + #define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */ 155 + #define TCOv2_TMR TCOBASE + 0x12 /* TCOv2 Timer Initial Value */ 156 + 157 + /* internal variables */ 158 + static unsigned long is_active; 159 + static char expect_release; 160 + static struct { /* this is private data for the iTCO_wdt device */ 161 + unsigned int iTCO_version; /* TCO version/generation */ 162 + unsigned long ACPIBASE; /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ 163 + unsigned long __iomem *gcs; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */ 164 + spinlock_t io_lock; /* the lock for io operations */ 165 + struct pci_dev *pdev; /* the PCI-device */ 166 + } iTCO_wdt_private; 167 + 168 + static struct platform_device *iTCO_wdt_platform_device; /* the watchdog platform device */ 169 + 170 + /* module parameters */ 171 + #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ 172 + static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ 173 + module_param(heartbeat, int, 0); 174 + MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); 175 + 176 + static int nowayout = WATCHDOG_NOWAYOUT; 177 + module_param(nowayout, int, 0); 178 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); 179 + 180 + /* 181 + * Some TCO specific functions 182 + */ 183 + 184 + static inline unsigned int seconds_to_ticks(int seconds) 185 + { 186 + /* the internal timer is stored as ticks which decrement 187 + * every 0.6 seconds */ 188 + return (seconds * 10) / 6; 189 + } 190 + 191 + static void iTCO_wdt_set_NO_REBOOT_bit(void) 192 + { 193 + u32 val32; 194 + 195 + /* Set the NO_REBOOT bit: this disables reboots */ 196 + if (iTCO_wdt_private.iTCO_version == 2) { 197 + val32 = readl(iTCO_wdt_private.gcs); 198 + val32 |= 0x00000020; 199 + writel(val32, iTCO_wdt_private.gcs); 200 + } else if (iTCO_wdt_private.iTCO_version == 1) { 201 + pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); 202 + val32 |= 0x00000002; 203 + pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); 204 + } 205 + } 206 + 207 + static int iTCO_wdt_unset_NO_REBOOT_bit(void) 208 + { 209 + int ret = 0; 210 + u32 val32; 211 + 212 + /* Unset the NO_REBOOT bit: this enables reboots */ 213 + if (iTCO_wdt_private.iTCO_version == 2) { 214 + val32 = readl(iTCO_wdt_private.gcs); 215 + val32 &= 0xffffffdf; 216 + writel(val32, iTCO_wdt_private.gcs); 217 + 218 + val32 = readl(iTCO_wdt_private.gcs); 219 + if (val32 & 0x00000020) 220 + ret = -EIO; 221 + } else if (iTCO_wdt_private.iTCO_version == 1) { 222 + pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); 223 + val32 &= 0xfffffffd; 224 + pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); 225 + 226 + pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); 227 + if (val32 & 0x00000002) 228 + ret = -EIO; 229 + } 230 + 231 + return ret; /* returns: 0 = OK, -EIO = Error */ 232 + } 233 + 234 + static int iTCO_wdt_start(void) 235 + { 236 + unsigned int val; 237 + 238 + spin_lock(&iTCO_wdt_private.io_lock); 239 + 240 + /* disable chipset's NO_REBOOT bit */ 241 + if (iTCO_wdt_unset_NO_REBOOT_bit()) { 242 + printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); 243 + return -EIO; 244 + } 245 + 246 + /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ 247 + val = inw(TCO1_CNT); 248 + val &= 0xf7ff; 249 + outw(val, TCO1_CNT); 250 + val = inw(TCO1_CNT); 251 + spin_unlock(&iTCO_wdt_private.io_lock); 252 + 253 + if (val & 0x0800) 254 + return -1; 255 + return 0; 256 + } 257 + 258 + static int iTCO_wdt_stop(void) 259 + { 260 + unsigned int val; 261 + 262 + spin_lock(&iTCO_wdt_private.io_lock); 263 + 264 + /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ 265 + val = inw(TCO1_CNT); 266 + val |= 0x0800; 267 + outw(val, TCO1_CNT); 268 + val = inw(TCO1_CNT); 269 + 270 + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ 271 + iTCO_wdt_set_NO_REBOOT_bit(); 272 + 273 + spin_unlock(&iTCO_wdt_private.io_lock); 274 + 275 + if ((val & 0x0800) == 0) 276 + return -1; 277 + return 0; 278 + } 279 + 280 + static int iTCO_wdt_keepalive(void) 281 + { 282 + spin_lock(&iTCO_wdt_private.io_lock); 283 + 284 + /* Reload the timer by writing to the TCO Timer Counter register */ 285 + if (iTCO_wdt_private.iTCO_version == 2) { 286 + outw(0x01, TCO_RLD); 287 + } else if (iTCO_wdt_private.iTCO_version == 1) { 288 + outb(0x01, TCO_RLD); 289 + } 290 + 291 + spin_unlock(&iTCO_wdt_private.io_lock); 292 + return 0; 293 + } 294 + 295 + static int iTCO_wdt_set_heartbeat(int t) 296 + { 297 + unsigned int val16; 298 + unsigned char val8; 299 + unsigned int tmrval; 300 + 301 + tmrval = seconds_to_ticks(t); 302 + /* from the specs: */ 303 + /* "Values of 0h-3h are ignored and should not be attempted" */ 304 + if (tmrval < 0x04) 305 + return -EINVAL; 306 + if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) || 307 + ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) 308 + return -EINVAL; 309 + 310 + /* Write new heartbeat to watchdog */ 311 + if (iTCO_wdt_private.iTCO_version == 2) { 312 + spin_lock(&iTCO_wdt_private.io_lock); 313 + val16 = inw(TCOv2_TMR); 314 + val16 &= 0xfc00; 315 + val16 |= tmrval; 316 + outw(val16, TCOv2_TMR); 317 + val16 = inw(TCOv2_TMR); 318 + spin_unlock(&iTCO_wdt_private.io_lock); 319 + 320 + if ((val16 & 0x3ff) != tmrval) 321 + return -EINVAL; 322 + } else if (iTCO_wdt_private.iTCO_version == 1) { 323 + spin_lock(&iTCO_wdt_private.io_lock); 324 + val8 = inb(TCOv1_TMR); 325 + val8 &= 0xc0; 326 + val8 |= (tmrval & 0xff); 327 + outb(val8, TCOv1_TMR); 328 + val8 = inb(TCOv1_TMR); 329 + spin_unlock(&iTCO_wdt_private.io_lock); 330 + 331 + if ((val8 & 0x3f) != tmrval) 332 + return -EINVAL; 333 + } 334 + 335 + heartbeat = t; 336 + return 0; 337 + } 338 + 339 + static int iTCO_wdt_get_timeleft (int *time_left) 340 + { 341 + unsigned int val16; 342 + unsigned char val8; 343 + 344 + /* read the TCO Timer */ 345 + if (iTCO_wdt_private.iTCO_version == 2) { 346 + spin_lock(&iTCO_wdt_private.io_lock); 347 + val16 = inw(TCO_RLD); 348 + val16 &= 0x3ff; 349 + spin_unlock(&iTCO_wdt_private.io_lock); 350 + 351 + *time_left = (val16 * 6) / 10; 352 + } else if (iTCO_wdt_private.iTCO_version == 1) { 353 + spin_lock(&iTCO_wdt_private.io_lock); 354 + val8 = inb(TCO_RLD); 355 + val8 &= 0x3f; 356 + spin_unlock(&iTCO_wdt_private.io_lock); 357 + 358 + *time_left = (val8 * 6) / 10; 359 + } 360 + return 0; 361 + } 362 + 363 + /* 364 + * /dev/watchdog handling 365 + */ 366 + 367 + static int iTCO_wdt_open (struct inode *inode, struct file *file) 368 + { 369 + /* /dev/watchdog can only be opened once */ 370 + if (test_and_set_bit(0, &is_active)) 371 + return -EBUSY; 372 + 373 + /* 374 + * Reload and activate timer 375 + */ 376 + iTCO_wdt_keepalive(); 377 + iTCO_wdt_start(); 378 + return nonseekable_open(inode, file); 379 + } 380 + 381 + static int iTCO_wdt_release (struct inode *inode, struct file *file) 382 + { 383 + /* 384 + * Shut off the timer. 385 + */ 386 + if (expect_release == 42) { 387 + iTCO_wdt_stop(); 388 + } else { 389 + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); 390 + iTCO_wdt_keepalive(); 391 + } 392 + clear_bit(0, &is_active); 393 + expect_release = 0; 394 + return 0; 395 + } 396 + 397 + static ssize_t iTCO_wdt_write (struct file *file, const char __user *data, 398 + size_t len, loff_t * ppos) 399 + { 400 + /* See if we got the magic character 'V' and reload the timer */ 401 + if (len) { 402 + if (!nowayout) { 403 + size_t i; 404 + 405 + /* note: just in case someone wrote the magic character 406 + * five months ago... */ 407 + expect_release = 0; 408 + 409 + /* scan to see whether or not we got the magic character */ 410 + for (i = 0; i != len; i++) { 411 + char c; 412 + if (get_user(c, data+i)) 413 + return -EFAULT; 414 + if (c == 'V') 415 + expect_release = 42; 416 + } 417 + } 418 + 419 + /* someone wrote to us, we should reload the timer */ 420 + iTCO_wdt_keepalive(); 421 + } 422 + return len; 423 + } 424 + 425 + static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, 426 + unsigned int cmd, unsigned long arg) 427 + { 428 + int new_options, retval = -EINVAL; 429 + int new_heartbeat; 430 + int time_left; 431 + void __user *argp = (void __user *)arg; 432 + int __user *p = argp; 433 + static struct watchdog_info ident = { 434 + .options = WDIOF_SETTIMEOUT | 435 + WDIOF_KEEPALIVEPING | 436 + WDIOF_MAGICCLOSE, 437 + .firmware_version = 0, 438 + .identity = DRV_NAME, 439 + }; 440 + 441 + switch (cmd) { 442 + case WDIOC_GETSUPPORT: 443 + return copy_to_user(argp, &ident, 444 + sizeof (ident)) ? -EFAULT : 0; 445 + 446 + case WDIOC_GETSTATUS: 447 + case WDIOC_GETBOOTSTATUS: 448 + return put_user(0, p); 449 + 450 + case WDIOC_KEEPALIVE: 451 + iTCO_wdt_keepalive(); 452 + return 0; 453 + 454 + case WDIOC_SETOPTIONS: 455 + { 456 + if (get_user(new_options, p)) 457 + return -EFAULT; 458 + 459 + if (new_options & WDIOS_DISABLECARD) { 460 + iTCO_wdt_stop(); 461 + retval = 0; 462 + } 463 + 464 + if (new_options & WDIOS_ENABLECARD) { 465 + iTCO_wdt_keepalive(); 466 + iTCO_wdt_start(); 467 + retval = 0; 468 + } 469 + 470 + return retval; 471 + } 472 + 473 + case WDIOC_SETTIMEOUT: 474 + { 475 + if (get_user(new_heartbeat, p)) 476 + return -EFAULT; 477 + 478 + if (iTCO_wdt_set_heartbeat(new_heartbeat)) 479 + return -EINVAL; 480 + 481 + iTCO_wdt_keepalive(); 482 + /* Fall */ 483 + } 484 + 485 + case WDIOC_GETTIMEOUT: 486 + return put_user(heartbeat, p); 487 + 488 + case WDIOC_GETTIMELEFT: 489 + { 490 + if (iTCO_wdt_get_timeleft(&time_left)) 491 + return -EINVAL; 492 + 493 + return put_user(time_left, p); 494 + } 495 + 496 + default: 497 + return -ENOIOCTLCMD; 498 + } 499 + } 500 + 501 + /* 502 + * Kernel Interfaces 503 + */ 504 + 505 + static struct file_operations iTCO_wdt_fops = { 506 + .owner = THIS_MODULE, 507 + .llseek = no_llseek, 508 + .write = iTCO_wdt_write, 509 + .ioctl = iTCO_wdt_ioctl, 510 + .open = iTCO_wdt_open, 511 + .release = iTCO_wdt_release, 512 + }; 513 + 514 + static struct miscdevice iTCO_wdt_miscdev = { 515 + .minor = WATCHDOG_MINOR, 516 + .name = "watchdog", 517 + .fops = &iTCO_wdt_fops, 518 + }; 519 + 520 + /* 521 + * Init & exit routines 522 + */ 523 + 524 + static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev) 525 + { 526 + int ret; 527 + u32 base_address; 528 + unsigned long RCBA; 529 + unsigned long val32; 530 + 531 + /* 532 + * Find the ACPI/PM base I/O address which is the base 533 + * for the TCO registers (TCOBASE=ACPIBASE + 0x60) 534 + * ACPIBASE is bits [15:7] from 0x40-0x43 535 + */ 536 + pci_read_config_dword(pdev, 0x40, &base_address); 537 + base_address &= 0x00007f80; 538 + if (base_address == 0x00000000) { 539 + /* Something's wrong here, ACPIBASE has to be set */ 540 + printk(KERN_ERR PFX "failed to get TCOBASE address\n"); 541 + pci_dev_put(pdev); 542 + return -ENODEV; 543 + } 544 + iTCO_wdt_private.iTCO_version = iTCO_chipset_info[ent->driver_data].iTCO_version; 545 + iTCO_wdt_private.ACPIBASE = base_address; 546 + iTCO_wdt_private.pdev = pdev; 547 + 548 + /* Get the Memory-Mapped GCS register, we need it for the NO_REBOOT flag (TCO v2) */ 549 + /* To get access to it you have to read RCBA from PCI Config space 0xf0 550 + and use it as base. GCS = RCBA + ICH6_GCS(0x3410). */ 551 + if (iTCO_wdt_private.iTCO_version == 2) { 552 + pci_read_config_dword(pdev, 0xf0, &base_address); 553 + RCBA = base_address & 0xffffc000; 554 + iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410),4); 555 + } 556 + 557 + /* Check chipset's NO_REBOOT bit */ 558 + if (iTCO_wdt_unset_NO_REBOOT_bit()) { 559 + printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); 560 + ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ 561 + goto out; 562 + } 563 + 564 + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ 565 + iTCO_wdt_set_NO_REBOOT_bit(); 566 + 567 + /* Set the TCO_EN bit in SMI_EN register */ 568 + if (!request_region(SMI_EN, 4, "iTCO_wdt")) { 569 + printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", 570 + SMI_EN ); 571 + ret = -EIO; 572 + goto out; 573 + } 574 + val32 = inl(SMI_EN); 575 + val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ 576 + outl(val32, SMI_EN); 577 + release_region(SMI_EN, 4); 578 + 579 + /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */ 580 + if (!request_region (TCOBASE, 0x20, "iTCO_wdt")) { 581 + printk (KERN_ERR PFX "I/O address 0x%04lx already in use\n", 582 + TCOBASE); 583 + ret = -EIO; 584 + goto out; 585 + } 586 + 587 + printk(KERN_INFO PFX "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n", 588 + iTCO_chipset_info[ent->driver_data].name, 589 + iTCO_chipset_info[ent->driver_data].iTCO_version, 590 + TCOBASE); 591 + 592 + /* Clear out the (probably old) status */ 593 + outb(0, TCO1_STS); 594 + outb(3, TCO2_STS); 595 + 596 + /* Make sure the watchdog is not running */ 597 + iTCO_wdt_stop(); 598 + 599 + /* Check that the heartbeat value is within it's range ; if not reset to the default */ 600 + if (iTCO_wdt_set_heartbeat(heartbeat)) { 601 + iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT); 602 + printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39 (TCO v1) or 613 (TCO v2), using %d\n", 603 + heartbeat); 604 + } 605 + 606 + ret = misc_register(&iTCO_wdt_miscdev); 607 + if (ret != 0) { 608 + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 609 + WATCHDOG_MINOR, ret); 610 + goto unreg_region; 611 + } 612 + 613 + printk (KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", 614 + heartbeat, nowayout); 615 + 616 + return 0; 617 + 618 + unreg_region: 619 + release_region (TCOBASE, 0x20); 620 + out: 621 + if (iTCO_wdt_private.iTCO_version == 2) 622 + iounmap(iTCO_wdt_private.gcs); 623 + pci_dev_put(iTCO_wdt_private.pdev); 624 + iTCO_wdt_private.ACPIBASE = 0; 625 + return ret; 626 + } 627 + 628 + static void iTCO_wdt_cleanup(void) 629 + { 630 + /* Stop the timer before we leave */ 631 + if (!nowayout) 632 + iTCO_wdt_stop(); 633 + 634 + /* Deregister */ 635 + misc_deregister(&iTCO_wdt_miscdev); 636 + release_region(TCOBASE, 0x20); 637 + if (iTCO_wdt_private.iTCO_version == 2) 638 + iounmap(iTCO_wdt_private.gcs); 639 + pci_dev_put(iTCO_wdt_private.pdev); 640 + iTCO_wdt_private.ACPIBASE = 0; 641 + } 642 + 643 + static int iTCO_wdt_probe(struct platform_device *dev) 644 + { 645 + int found = 0; 646 + struct pci_dev *pdev = NULL; 647 + const struct pci_device_id *ent; 648 + 649 + spin_lock_init(&iTCO_wdt_private.io_lock); 650 + 651 + for_each_pci_dev(pdev) { 652 + ent = pci_match_id(iTCO_wdt_pci_tbl, pdev); 653 + if (ent) { 654 + if (!(iTCO_wdt_init(pdev, ent, dev))) { 655 + found++; 656 + break; 657 + } 658 + } 659 + } 660 + 661 + if (!found) { 662 + printk(KERN_INFO PFX "No card detected\n"); 663 + return -ENODEV; 664 + } 665 + 666 + return 0; 667 + } 668 + 669 + static int iTCO_wdt_remove(struct platform_device *dev) 670 + { 671 + if (iTCO_wdt_private.ACPIBASE) 672 + iTCO_wdt_cleanup(); 673 + 674 + return 0; 675 + } 676 + 677 + static void iTCO_wdt_shutdown(struct platform_device *dev) 678 + { 679 + iTCO_wdt_stop(); 680 + } 681 + 682 + #define iTCO_wdt_suspend NULL 683 + #define iTCO_wdt_resume NULL 684 + 685 + static struct platform_driver iTCO_wdt_driver = { 686 + .probe = iTCO_wdt_probe, 687 + .remove = iTCO_wdt_remove, 688 + .shutdown = iTCO_wdt_shutdown, 689 + .suspend = iTCO_wdt_suspend, 690 + .resume = iTCO_wdt_resume, 691 + .driver = { 692 + .owner = THIS_MODULE, 693 + .name = DRV_NAME, 694 + }, 695 + }; 696 + 697 + static int __init iTCO_wdt_init_module(void) 698 + { 699 + int err; 700 + 701 + printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s (%s)\n", 702 + DRV_VERSION, DRV_RELDATE); 703 + 704 + err = platform_driver_register(&iTCO_wdt_driver); 705 + if (err) 706 + return err; 707 + 708 + iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); 709 + if (IS_ERR(iTCO_wdt_platform_device)) { 710 + err = PTR_ERR(iTCO_wdt_platform_device); 711 + goto unreg_platform_driver; 712 + } 713 + 714 + return 0; 715 + 716 + unreg_platform_driver: 717 + platform_driver_unregister(&iTCO_wdt_driver); 718 + return err; 719 + } 720 + 721 + static void __exit iTCO_wdt_cleanup_module(void) 722 + { 723 + platform_device_unregister(iTCO_wdt_platform_device); 724 + platform_driver_unregister(&iTCO_wdt_driver); 725 + printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); 726 + } 727 + 728 + module_init(iTCO_wdt_init_module); 729 + module_exit(iTCO_wdt_cleanup_module); 730 + 731 + MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); 732 + MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver"); 733 + MODULE_VERSION(DRV_VERSION); 734 + MODULE_LICENSE("GPL"); 735 + MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);