diff options
Diffstat (limited to 'drivers/char/watchdog/iTCO_wdt.c')
-rw-r--r-- | drivers/char/watchdog/iTCO_wdt.c | 48 |
1 files changed, 43 insertions, 5 deletions
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index aaac94db0d8b..7eac922df867 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c | |||
@@ -35,6 +35,10 @@ | |||
35 | * 82801GDH (ICH7DH) : 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, | 36 | * 82801GBM (ICH7-M) : document number 307013-002, 307014-009, |
37 | * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, | 37 | * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, |
38 | * 82801HB (ICH8) : document number 313056-002, 313057-004, | ||
39 | * 82801HR (ICH8R) : document number 313056-002, 313057-004, | ||
40 | * 82801HH (ICH8DH) : document number 313056-002, 313057-004, | ||
41 | * 82801HO (ICH8DO) : document number 313056-002, 313057-004, | ||
38 | * 6300ESB (6300ESB) : document number 300641-003 | 42 | * 6300ESB (6300ESB) : document number 300641-003 |
39 | */ | 43 | */ |
40 | 44 | ||
@@ -44,8 +48,8 @@ | |||
44 | 48 | ||
45 | /* Module and version information */ | 49 | /* Module and version information */ |
46 | #define DRV_NAME "iTCO_wdt" | 50 | #define DRV_NAME "iTCO_wdt" |
47 | #define DRV_VERSION "1.00" | 51 | #define DRV_VERSION "1.01" |
48 | #define DRV_RELDATE "30-Jul-2006" | 52 | #define DRV_RELDATE "11-Nov-2006" |
49 | #define PFX DRV_NAME ": " | 53 | #define PFX DRV_NAME ": " |
50 | 54 | ||
51 | /* Includes */ | 55 | /* Includes */ |
@@ -85,6 +89,9 @@ enum iTCO_chipsets { | |||
85 | TCO_ICH7, /* ICH7 & ICH7R */ | 89 | TCO_ICH7, /* ICH7 & ICH7R */ |
86 | TCO_ICH7M, /* ICH7-M */ | 90 | TCO_ICH7M, /* ICH7-M */ |
87 | TCO_ICH7MDH, /* ICH7-M DH */ | 91 | TCO_ICH7MDH, /* ICH7-M DH */ |
92 | TCO_ICH8, /* ICH8 & ICH8R */ | ||
93 | TCO_ICH8DH, /* ICH8DH */ | ||
94 | TCO_ICH8DO, /* ICH8DO */ | ||
88 | }; | 95 | }; |
89 | 96 | ||
90 | static struct { | 97 | static struct { |
@@ -108,6 +115,9 @@ static struct { | |||
108 | {"ICH7 or ICH7R", 2}, | 115 | {"ICH7 or ICH7R", 2}, |
109 | {"ICH7-M", 2}, | 116 | {"ICH7-M", 2}, |
110 | {"ICH7-M DH", 2}, | 117 | {"ICH7-M DH", 2}, |
118 | {"ICH8 or ICH8R", 2}, | ||
119 | {"ICH8DH", 2}, | ||
120 | {"ICH8DO", 2}, | ||
111 | {NULL,0} | 121 | {NULL,0} |
112 | }; | 122 | }; |
113 | 123 | ||
@@ -135,6 +145,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { | |||
135 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, | 145 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, |
136 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, | 146 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, |
137 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, | 147 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, |
148 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 }, | ||
149 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH }, | ||
150 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO }, | ||
138 | { 0, }, /* End of list */ | 151 | { 0, }, /* End of list */ |
139 | }; | 152 | }; |
140 | MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); | 153 | MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); |
@@ -176,6 +189,21 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
176 | module_param(nowayout, int, 0); | 189 | module_param(nowayout, int, 0); |
177 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | 190 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); |
178 | 191 | ||
192 | /* iTCO Vendor Specific Support hooks */ | ||
193 | #ifdef CONFIG_ITCO_VENDOR_SUPPORT | ||
194 | extern void iTCO_vendor_pre_start(unsigned long, unsigned int); | ||
195 | extern void iTCO_vendor_pre_stop(unsigned long); | ||
196 | extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int); | ||
197 | extern void iTCO_vendor_pre_set_heartbeat(unsigned int); | ||
198 | extern int iTCO_vendor_check_noreboot_on(void); | ||
199 | #else | ||
200 | #define iTCO_vendor_pre_start(acpibase, heartbeat) {} | ||
201 | #define iTCO_vendor_pre_stop(acpibase) {} | ||
202 | #define iTCO_vendor_pre_keepalive(acpibase,heartbeat) {} | ||
203 | #define iTCO_vendor_pre_set_heartbeat(heartbeat) {} | ||
204 | #define iTCO_vendor_check_noreboot_on() 1 /* 1=check noreboot; 0=don't check */ | ||
205 | #endif | ||
206 | |||
179 | /* | 207 | /* |
180 | * Some TCO specific functions | 208 | * Some TCO specific functions |
181 | */ | 209 | */ |
@@ -236,6 +264,8 @@ static int iTCO_wdt_start(void) | |||
236 | 264 | ||
237 | spin_lock(&iTCO_wdt_private.io_lock); | 265 | spin_lock(&iTCO_wdt_private.io_lock); |
238 | 266 | ||
267 | iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat); | ||
268 | |||
239 | /* disable chipset's NO_REBOOT bit */ | 269 | /* disable chipset's NO_REBOOT bit */ |
240 | if (iTCO_wdt_unset_NO_REBOOT_bit()) { | 270 | if (iTCO_wdt_unset_NO_REBOOT_bit()) { |
241 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); | 271 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); |
@@ -260,6 +290,8 @@ static int iTCO_wdt_stop(void) | |||
260 | 290 | ||
261 | spin_lock(&iTCO_wdt_private.io_lock); | 291 | spin_lock(&iTCO_wdt_private.io_lock); |
262 | 292 | ||
293 | iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE); | ||
294 | |||
263 | /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ | 295 | /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ |
264 | val = inw(TCO1_CNT); | 296 | val = inw(TCO1_CNT); |
265 | val |= 0x0800; | 297 | val |= 0x0800; |
@@ -280,6 +312,8 @@ static int iTCO_wdt_keepalive(void) | |||
280 | { | 312 | { |
281 | spin_lock(&iTCO_wdt_private.io_lock); | 313 | spin_lock(&iTCO_wdt_private.io_lock); |
282 | 314 | ||
315 | iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat); | ||
316 | |||
283 | /* Reload the timer by writing to the TCO Timer Counter register */ | 317 | /* Reload the timer by writing to the TCO Timer Counter register */ |
284 | if (iTCO_wdt_private.iTCO_version == 2) { | 318 | if (iTCO_wdt_private.iTCO_version == 2) { |
285 | outw(0x01, TCO_RLD); | 319 | outw(0x01, TCO_RLD); |
@@ -306,6 +340,8 @@ static int iTCO_wdt_set_heartbeat(int t) | |||
306 | ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) | 340 | ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) |
307 | return -EINVAL; | 341 | return -EINVAL; |
308 | 342 | ||
343 | iTCO_vendor_pre_set_heartbeat(tmrval); | ||
344 | |||
309 | /* Write new heartbeat to watchdog */ | 345 | /* Write new heartbeat to watchdog */ |
310 | if (iTCO_wdt_private.iTCO_version == 2) { | 346 | if (iTCO_wdt_private.iTCO_version == 2) { |
311 | spin_lock(&iTCO_wdt_private.io_lock); | 347 | spin_lock(&iTCO_wdt_private.io_lock); |
@@ -355,7 +391,8 @@ static int iTCO_wdt_get_timeleft (int *time_left) | |||
355 | spin_unlock(&iTCO_wdt_private.io_lock); | 391 | spin_unlock(&iTCO_wdt_private.io_lock); |
356 | 392 | ||
357 | *time_left = (val8 * 6) / 10; | 393 | *time_left = (val8 * 6) / 10; |
358 | } | 394 | } else |
395 | return -EINVAL; | ||
359 | return 0; | 396 | return 0; |
360 | } | 397 | } |
361 | 398 | ||
@@ -426,7 +463,6 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | |||
426 | { | 463 | { |
427 | int new_options, retval = -EINVAL; | 464 | int new_options, retval = -EINVAL; |
428 | int new_heartbeat; | 465 | int new_heartbeat; |
429 | int time_left; | ||
430 | void __user *argp = (void __user *)arg; | 466 | void __user *argp = (void __user *)arg; |
431 | int __user *p = argp; | 467 | int __user *p = argp; |
432 | static struct watchdog_info ident = { | 468 | static struct watchdog_info ident = { |
@@ -486,6 +522,8 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | |||
486 | 522 | ||
487 | case WDIOC_GETTIMELEFT: | 523 | case WDIOC_GETTIMELEFT: |
488 | { | 524 | { |
525 | int time_left; | ||
526 | |||
489 | if (iTCO_wdt_get_timeleft(&time_left)) | 527 | if (iTCO_wdt_get_timeleft(&time_left)) |
490 | return -EINVAL; | 528 | return -EINVAL; |
491 | 529 | ||
@@ -554,7 +592,7 @@ static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, | |||
554 | } | 592 | } |
555 | 593 | ||
556 | /* Check chipset's NO_REBOOT bit */ | 594 | /* Check chipset's NO_REBOOT bit */ |
557 | if (iTCO_wdt_unset_NO_REBOOT_bit()) { | 595 | if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { |
558 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); | 596 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); |
559 | ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ | 597 | ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ |
560 | goto out; | 598 | goto out; |