aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog/pcwd_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/watchdog/pcwd_pci.c')
-rw-r--r--drivers/char/watchdog/pcwd_pci.c175
1 files changed, 108 insertions, 67 deletions
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
index 5a80adbf8032..0cb62e39e58f 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -50,8 +50,8 @@
50#include <asm/io.h> /* For inb/outb/... */ 50#include <asm/io.h> /* For inb/outb/... */
51 51
52/* Module and version information */ 52/* Module and version information */
53#define WATCHDOG_VERSION "1.01" 53#define WATCHDOG_VERSION "1.02"
54#define WATCHDOG_DATE "02 Sep 2005" 54#define WATCHDOG_DATE "03 Sep 2005"
55#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog" 55#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
56#define WATCHDOG_NAME "pcwd_pci" 56#define WATCHDOG_NAME "pcwd_pci"
57#define PFX WATCHDOG_NAME ": " 57#define PFX WATCHDOG_NAME ": "
@@ -70,19 +70,30 @@
70 * These are the defines that describe the control status bits for the 70 * These are the defines that describe the control status bits for the
71 * PCI-PC Watchdog card. 71 * PCI-PC Watchdog card.
72 */ 72 */
73#define WD_PCI_WTRP 0x01 /* Watchdog Trip status */ 73/* Port 1 : Control Status #1 */
74#define WD_PCI_HRBT 0x02 /* Watchdog Heartbeat */ 74#define WD_PCI_WTRP 0x01 /* Watchdog Trip status */
75#define WD_PCI_TTRP 0x04 /* Temperature Trip status */ 75#define WD_PCI_HRBT 0x02 /* Watchdog Heartbeat */
76#define WD_PCI_TTRP 0x04 /* Temperature Trip status */
77#define WD_PCI_RL2A 0x08 /* Relay 2 Active */
78#define WD_PCI_RL1A 0x10 /* Relay 1 Active */
79#define WD_PCI_R2DS 0x40 /* Relay 2 Disable Temperature-trip/reset */
80#define WD_PCI_RLY2 0x80 /* Activate Relay 2 on the board */
81/* Port 2 : Control Status #2 */
82#define WD_PCI_WDIS 0x10 /* Watchdog Disable */
83#define WD_PCI_ENTP 0x20 /* Enable Temperature Trip Reset */
84#define WD_PCI_WRSP 0x40 /* Watchdog wrote response */
85#define WD_PCI_PCMD 0x80 /* PC has sent command */
76 86
77/* according to documentation max. time to process a command for the pci 87/* according to documentation max. time to process a command for the pci
78 * watchdog card is 100 ms, so we give it 150 ms to do it's job */ 88 * watchdog card is 100 ms, so we give it 150 ms to do it's job */
79#define PCI_COMMAND_TIMEOUT 150 89#define PCI_COMMAND_TIMEOUT 150
80 90
81/* Watchdog's internal commands */ 91/* Watchdog's internal commands */
82#define CMD_GET_STATUS 0x04 92#define CMD_GET_STATUS 0x04
83#define CMD_GET_FIRMWARE_VERSION 0x08 93#define CMD_GET_FIRMWARE_VERSION 0x08
84#define CMD_READ_WATCHDOG_TIMEOUT 0x18 94#define CMD_READ_WATCHDOG_TIMEOUT 0x18
85#define CMD_WRITE_WATCHDOG_TIMEOUT 0x19 95#define CMD_WRITE_WATCHDOG_TIMEOUT 0x19
96#define CMD_GET_CLEAR_RESET_COUNT 0x84
86 97
87/* We can only use 1 card due to the /dev/watchdog restriction */ 98/* We can only use 1 card due to the /dev/watchdog restriction */
88static int cards_found; 99static int cards_found;
@@ -91,12 +102,12 @@ static int cards_found;
91static int temp_panic; 102static int temp_panic;
92static unsigned long is_active; 103static unsigned long is_active;
93static char expect_release; 104static char expect_release;
94static struct { 105static struct { /* this is private data for each PCI-PC watchdog card */
95 int supports_temp; /* Wether or not the card has a temperature device */ 106 int supports_temp; /* Wether or not the card has a temperature device */
96 int boot_status; /* The card's boot status */ 107 int boot_status; /* The card's boot status */
97 unsigned long io_addr; /* The cards I/O address */ 108 unsigned long io_addr; /* The cards I/O address */
98 spinlock_t io_lock; 109 spinlock_t io_lock; /* the lock for io operations */
99 struct pci_dev *pdev; 110 struct pci_dev *pdev; /* the PCI-device */
100} pcipcwd_private; 111} pcipcwd_private;
101 112
102/* module parameters */ 113/* module parameters */
@@ -131,10 +142,10 @@ static int send_command(int cmd, int *msb, int *lsb)
131 /* wait till the pci card processed the command, signaled by 142 /* wait till the pci card processed the command, signaled by
132 * the WRSP bit in port 2 and give it a max. timeout of 143 * the WRSP bit in port 2 and give it a max. timeout of
133 * PCI_COMMAND_TIMEOUT to process */ 144 * PCI_COMMAND_TIMEOUT to process */
134 got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40; 145 got_response = inb_p(pcipcwd_private.io_addr + 2) & WD_PCI_WRSP;
135 for (count = 0; (count < PCI_COMMAND_TIMEOUT) && (!got_response); count++) { 146 for (count = 0; (count < PCI_COMMAND_TIMEOUT) && (!got_response); count++) {
136 mdelay(1); 147 mdelay(1);
137 got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40; 148 got_response = inb_p(pcipcwd_private.io_addr + 2) & WD_PCI_WRSP;
138 } 149 }
139 150
140 if (got_response) { 151 if (got_response) {
@@ -150,6 +161,55 @@ static int send_command(int cmd, int *msb, int *lsb)
150 return got_response; 161 return got_response;
151} 162}
152 163
164static inline void pcipcwd_check_temperature_support(void)
165{
166 if (inb_p(pcipcwd_private.io_addr) != 0xF0)
167 pcipcwd_private.supports_temp = 1;
168}
169
170static int pcipcwd_get_option_switches(void)
171{
172 int option_switches;
173
174 option_switches = inb_p(pcipcwd_private.io_addr + 3);
175 return option_switches;
176}
177
178static void pcipcwd_show_card_info(void)
179{
180 int got_fw_rev, fw_rev_major, fw_rev_minor;
181 char fw_ver_str[20]; /* The cards firmware version */
182 int option_switches;
183
184 got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
185 if (got_fw_rev) {
186 sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
187 } else {
188 sprintf(fw_ver_str, "<card no answer>");
189 }
190
191 /* Get switch settings */
192 option_switches = pcipcwd_get_option_switches();
193
194 printk(KERN_INFO PFX "Found card at port 0x%04x (Firmware: %s) %s temp option\n",
195 (int) pcipcwd_private.io_addr, fw_ver_str,
196 (pcipcwd_private.supports_temp ? "with" : "without"));
197
198 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
199 option_switches,
200 ((option_switches & 0x10) ? "ON" : "OFF"),
201 ((option_switches & 0x08) ? "ON" : "OFF"));
202
203 if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
204 printk(KERN_INFO PFX "Previous reset was caused by the Watchdog card\n");
205
206 if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
207 printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");
208
209 if (pcipcwd_private.boot_status == 0)
210 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
211}
212
153static int pcipcwd_start(void) 213static int pcipcwd_start(void)
154{ 214{
155 int stat_reg; 215 int stat_reg;
@@ -161,7 +221,7 @@ static int pcipcwd_start(void)
161 stat_reg = inb_p(pcipcwd_private.io_addr + 2); 221 stat_reg = inb_p(pcipcwd_private.io_addr + 2);
162 spin_unlock(&pcipcwd_private.io_lock); 222 spin_unlock(&pcipcwd_private.io_lock);
163 223
164 if (stat_reg & 0x10) { 224 if (stat_reg & WD_PCI_WDIS) {
165 printk(KERN_ERR PFX "Card timer not enabled\n"); 225 printk(KERN_ERR PFX "Card timer not enabled\n");
166 return -1; 226 return -1;
167 } 227 }
@@ -183,7 +243,7 @@ static int pcipcwd_stop(void)
183 stat_reg = inb_p(pcipcwd_private.io_addr + 2); 243 stat_reg = inb_p(pcipcwd_private.io_addr + 2);
184 spin_unlock(&pcipcwd_private.io_lock); 244 spin_unlock(&pcipcwd_private.io_lock);
185 245
186 if (!(stat_reg & 0x10)) { 246 if (!(stat_reg & WD_PCI_WDIS)) {
187 printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n"); 247 printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");
188 return -1; 248 return -1;
189 } 249 }
@@ -194,7 +254,7 @@ static int pcipcwd_stop(void)
194static int pcipcwd_keepalive(void) 254static int pcipcwd_keepalive(void)
195{ 255{
196 /* Re-trigger watchdog by writing to port 0 */ 256 /* Re-trigger watchdog by writing to port 0 */
197 outb_p(0x42, pcipcwd_private.io_addr); 257 outb_p(0x42, pcipcwd_private.io_addr); /* send out any data */
198 return 0; 258 return 0;
199} 259}
200 260
@@ -215,13 +275,13 @@ static int pcipcwd_set_heartbeat(int t)
215 275
216static int pcipcwd_get_status(int *status) 276static int pcipcwd_get_status(int *status)
217{ 277{
218 int new_status; 278 int control_status;
219 279
220 *status=0; 280 *status=0;
221 new_status = inb_p(pcipcwd_private.io_addr + 1); 281 control_status = inb_p(pcipcwd_private.io_addr + 1);
222 if (new_status & WD_PCI_WTRP) 282 if (control_status & WD_PCI_WTRP)
223 *status |= WDIOF_CARDRESET; 283 *status |= WDIOF_CARDRESET;
224 if (new_status & WD_PCI_TTRP) { 284 if (control_status & WD_PCI_TTRP) {
225 *status |= WDIOF_OVERHEAT; 285 *status |= WDIOF_OVERHEAT;
226 if (temp_panic) 286 if (temp_panic)
227 panic(PFX "Temperature overheat trip!\n"); 287 panic(PFX "Temperature overheat trip!\n");
@@ -232,7 +292,20 @@ static int pcipcwd_get_status(int *status)
232 292
233static int pcipcwd_clear_status(void) 293static int pcipcwd_clear_status(void)
234{ 294{
235 outb_p(0x01, pcipcwd_private.io_addr + 1); 295 int control_status;
296 int msb;
297 int reset_counter;
298
299 control_status = inb_p(pcipcwd_private.io_addr + 1);
300
301 /* clear trip status & LED and keep mode of relay 2 */
302 outb_p((control_status & WD_PCI_R2DS) | WD_PCI_WTRP, pcipcwd_private.io_addr + 1);
303
304 /* clear reset counter */
305 msb=0;
306 reset_counter=0xff;
307 send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter);
308
236 return 0; 309 return 0;
237} 310}
238 311
@@ -242,11 +315,13 @@ static int pcipcwd_get_temperature(int *temperature)
242 if (!pcipcwd_private.supports_temp) 315 if (!pcipcwd_private.supports_temp)
243 return -ENODEV; 316 return -ENODEV;
244 317
318 *temperature = inb_p(pcipcwd_private.io_addr);
319
245 /* 320 /*
246 * Convert celsius to fahrenheit, since this was 321 * Convert celsius to fahrenheit, since this was
247 * the decided 'standard' for this return value. 322 * the decided 'standard' for this return value.
248 */ 323 */
249 *temperature = ((inb_p(pcipcwd_private.io_addr)) * 9 / 5) + 32; 324 *temperature = (*temperature * 9 / 5) + 32;
250 325
251 return 0; 326 return 0;
252} 327}
@@ -256,7 +331,7 @@ static int pcipcwd_get_temperature(int *temperature)
256 */ 331 */
257 332
258static ssize_t pcipcwd_write(struct file *file, const char __user *data, 333static ssize_t pcipcwd_write(struct file *file, const char __user *data,
259 size_t len, loff_t *ppos) 334 size_t len, loff_t *ppos)
260{ 335{
261 /* See if we got the magic character 'V' and reload the timer */ 336 /* See if we got the magic character 'V' and reload the timer */
262 if (len) { 337 if (len) {
@@ -381,8 +456,9 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
381static int pcipcwd_open(struct inode *inode, struct file *file) 456static int pcipcwd_open(struct inode *inode, struct file *file)
382{ 457{
383 /* /dev/watchdog can only be opened once */ 458 /* /dev/watchdog can only be opened once */
384 if (test_and_set_bit(0, &is_active)) 459 if (test_and_set_bit(0, &is_active)) {
385 return -EBUSY; 460 return -EBUSY;
461 }
386 462
387 /* Activate */ 463 /* Activate */
388 pcipcwd_start(); 464 pcipcwd_start();
@@ -492,19 +568,10 @@ static struct notifier_block pcipcwd_notifier = {
492 * Init & exit routines 568 * Init & exit routines
493 */ 569 */
494 570
495static inline void check_temperature_support(void)
496{
497 if (inb_p(pcipcwd_private.io_addr) != 0xF0)
498 pcipcwd_private.supports_temp = 1;
499}
500
501static int __devinit pcipcwd_card_init(struct pci_dev *pdev, 571static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
502 const struct pci_device_id *ent) 572 const struct pci_device_id *ent)
503{ 573{
504 int ret = -EIO; 574 int ret = -EIO;
505 int got_fw_rev, fw_rev_major, fw_rev_minor;
506 char fw_ver_str[20];
507 char option_switches;
508 575
509 cards_found++; 576 cards_found++;
510 if (cards_found == 1) 577 if (cards_found == 1)
@@ -546,36 +613,10 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
546 pcipcwd_stop(); 613 pcipcwd_stop();
547 614
548 /* Check whether or not the card supports the temperature device */ 615 /* Check whether or not the card supports the temperature device */
549 check_temperature_support(); 616 pcipcwd_check_temperature_support();
550
551 /* Get the Firmware Version */
552 got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
553 if (got_fw_rev) {
554 sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
555 } else {
556 sprintf(fw_ver_str, "<card no answer>");
557 }
558 617
559 /* Get switch settings */ 618 /* Show info about the card itself */
560 option_switches = inb_p(pcipcwd_private.io_addr + 3); 619 pcipcwd_show_card_info();
561
562 printk(KERN_INFO PFX "Found card at port 0x%04x (Firmware: %s) %s temp option\n",
563 (int) pcipcwd_private.io_addr, fw_ver_str,
564 (pcipcwd_private.supports_temp ? "with" : "without"));
565
566 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
567 option_switches,
568 ((option_switches & 0x10) ? "ON" : "OFF"),
569 ((option_switches & 0x08) ? "ON" : "OFF"));
570
571 if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
572 printk(KERN_INFO PFX "Previous reset was caused by the Watchdog card\n");
573
574 if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
575 printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");
576
577 if (pcipcwd_private.boot_status == 0)
578 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
579 620
580 /* Check that the heartbeat value is within it's range ; if not reset to the default */ 621 /* Check that the heartbeat value is within it's range ; if not reset to the default */
581 if (pcipcwd_set_heartbeat(heartbeat)) { 622 if (pcipcwd_set_heartbeat(heartbeat)) {
@@ -656,7 +697,7 @@ static struct pci_driver pcipcwd_driver = {
656 697
657static int __init pcipcwd_init_module(void) 698static int __init pcipcwd_init_module(void)
658{ 699{
659 spin_lock_init (&pcipcwd_private.io_lock); 700 spin_lock_init(&pcipcwd_private.io_lock);
660 701
661 return pci_register_driver(&pcipcwd_driver); 702 return pci_register_driver(&pcipcwd_driver);
662} 703}