1/* cpwatchdog.c - driver implementation for hardware watchdog 2 * timers found on Sun Microsystems CP1400 and CP1500 boards. 3 * 4 * This device supports both the generic Linux watchdog 5 * interface and Solaris-compatible ioctls as best it is 6 * able. 7 * 8 * NOTE: CP1400 systems appear to have a defective intr_mask 9 * register on the PLD, preventing the disabling of 10 * timer interrupts. We use a timer to periodically 11 * reset 'stopped' watchdogs on affected platforms. 12 * 13 * Copyright (c) 2000 Eric Brower (ebrower@usa.net) 14 */ 15 16#include <linux/kernel.h> 17#include <linux/module.h> 18#include <linux/fs.h> 19#include <linux/errno.h> 20#include <linux/major.h> 21#include <linux/init.h> 22#include <linux/miscdevice.h> 23#include <linux/interrupt.h> 24#include <linux/ioport.h> 25#include <linux/timer.h> 26#include <linux/smp_lock.h> 27#include <asm/irq.h> 28#include <asm/ebus.h> 29#include <asm/oplib.h> 30#include <asm/uaccess.h> 31 32#include <asm/watchdog.h> 33 34#define WD_OBPNAME "watchdog" 35#define WD_BADMODEL "SUNW,501-5336" 36#define WD_BTIMEOUT (jiffies + (HZ * 1000)) 37#define WD_BLIMIT 0xFFFF 38 39#define WD0_DEVNAME "watchdog0" 40#define WD1_DEVNAME "watchdog1" 41#define WD2_DEVNAME "watchdog2" 42 43#define WD0_MINOR 212 44#define WD1_MINOR 213 45#define WD2_MINOR 214 46 47 48/* Internal driver definitions 49 */ 50#define WD0_ID 0 /* Watchdog0 */ 51#define WD1_ID 1 /* Watchdog1 */ 52#define WD2_ID 2 /* Watchdog2 */ 53#define WD_NUMDEVS 3 /* Device contains 3 timers */ 54 55#define WD_INTR_OFF 0 /* Interrupt disable value */ 56#define WD_INTR_ON 1 /* Interrupt enable value */ 57 58#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */ 59#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */ 60#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */ 61 62/* Register value definitions 63 */ 64#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */ 65#define WD1_INTR_MASK 0x02 66#define WD2_INTR_MASK 0x04 67 68#define WD_S_RUNNING 0x01 /* Watchdog device status running */ 69#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */ 70 71/* Sun uses Altera PLD EPF8820ATC144-4 72 * providing three hardware watchdogs: 73 * 74 * 1) RIC - sends an interrupt when triggered 75 * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU 76 * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board 77 * 78 *** Timer register block definition (struct wd_timer_regblk) 79 * 80 * dcntr and limit registers (halfword access): 81 * ------------------- 82 * | 15 | ...| 1 | 0 | 83 * ------------------- 84 * |- counter val -| 85 * ------------------- 86 * dcntr - Current 16-bit downcounter value. 87 * When downcounter reaches '0' watchdog expires. 88 * Reading this register resets downcounter with 'limit' value. 89 * limit - 16-bit countdown value in 1/10th second increments. 90 * Writing this register begins countdown with input value. 91 * Reading from this register does not affect counter. 92 * NOTES: After watchdog reset, dcntr and limit contain '1' 93 * 94 * status register (byte access): 95 * --------------------------- 96 * | 7 | ... | 2 | 1 | 0 | 97 * --------------+------------ 98 * |- UNUSED -| EXP | RUN | 99 * --------------------------- 100 * status- Bit 0 - Watchdog is running 101 * Bit 1 - Watchdog has expired 102 * 103 *** PLD register block definition (struct wd_pld_regblk) 104 * 105 * intr_mask register (byte access): 106 * --------------------------------- 107 * | 7 | ... | 3 | 2 | 1 | 0 | 108 * +-------------+------------------ 109 * |- UNUSED -| WD3 | WD2 | WD1 | 110 * --------------------------------- 111 * WD3 - 1 == Interrupt disabled for watchdog 3 112 * WD2 - 1 == Interrupt disabled for watchdog 2 113 * WD1 - 1 == Interrupt disabled for watchdog 1 114 * 115 * pld_status register (byte access): 116 * UNKNOWN, MAGICAL MYSTERY REGISTER 117 * 118 */ 119#define WD_TIMER_REGSZ 16 120#define WD0_OFF 0 121#define WD1_OFF (WD_TIMER_REGSZ * 1) 122#define WD2_OFF (WD_TIMER_REGSZ * 2) 123#define PLD_OFF (WD_TIMER_REGSZ * 3) 124 125#define WD_DCNTR 0x00 126#define WD_LIMIT 0x04 127#define WD_STATUS 0x08 128 129#define PLD_IMASK (PLD_OFF + 0x00) 130#define PLD_STATUS (PLD_OFF + 0x04) 131 132/* Individual timer structure 133 */ 134struct wd_timer { 135 __u16 timeout; 136 __u8 intr_mask; 137 unsigned char runstatus; 138 void __iomem *regs; 139}; 140 141/* Device structure 142 */ 143struct wd_device { 144 int irq; 145 spinlock_t lock; 146 unsigned char isbaddoggie; /* defective PLD */ 147 unsigned char opt_enable; 148 unsigned char opt_reboot; 149 unsigned short opt_timeout; 150 unsigned char initialized; 151 struct wd_timer watchdog[WD_NUMDEVS]; 152 void __iomem *regs; 153}; 154 155static struct wd_device wd_dev = { 156 0, SPIN_LOCK_UNLOCKED, 0, 0, 0, 0, 157}; 158 159static struct timer_list wd_timer; 160 161static int wd0_timeout = 0; 162static int wd1_timeout = 0; 163static int wd2_timeout = 0; 164 165#ifdef MODULE 166module_param (wd0_timeout, int, 0); 167MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); 168module_param (wd1_timeout, int, 0); 169MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); 170module_param (wd2_timeout, int, 0); 171MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); 172 173MODULE_AUTHOR 174 ("Eric Brower <ebrower@usa.net>"); 175MODULE_DESCRIPTION 176 ("Hardware watchdog driver for Sun Microsystems CP1400/1500"); 177MODULE_LICENSE("GPL"); 178MODULE_SUPPORTED_DEVICE 179 ("watchdog"); 180#endif /* ifdef MODULE */ 181 182/* Forward declarations of internal methods 183 */ 184#ifdef WD_DEBUG 185static void wd_dumpregs(void); 186#endif 187static irqreturn_t wd_interrupt(int irq, void *dev_id); 188static void wd_toggleintr(struct wd_timer* pTimer, int enable); 189static void wd_pingtimer(struct wd_timer* pTimer); 190static void wd_starttimer(struct wd_timer* pTimer); 191static void wd_resetbrokentimer(struct wd_timer* pTimer); 192static void wd_stoptimer(struct wd_timer* pTimer); 193static void wd_brokentimer(unsigned long data); 194static int wd_getstatus(struct wd_timer* pTimer); 195 196/* PLD expects words to be written in LSB format, 197 * so we must flip all words prior to writing them to regs 198 */ 199static inline unsigned short flip_word(unsigned short word) 200{ 201 return ((word & 0xff) << 8) | ((word >> 8) & 0xff); 202} 203 204#define wd_writew(val, addr) (writew(flip_word(val), addr)) 205#define wd_readw(addr) (flip_word(readw(addr))) 206#define wd_writeb(val, addr) (writeb(val, addr)) 207#define wd_readb(addr) (readb(addr)) 208 209 210/* CP1400s seem to have broken PLD implementations-- 211 * the interrupt_mask register cannot be written, so 212 * no timer interrupts can be masked within the PLD. 213 */ 214static inline int wd_isbroken(void) 215{ 216 /* we could test this by read/write/read/restore 217 * on the interrupt mask register only if OBP 218 * 'watchdog-enable?' == FALSE, but it seems 219 * ubiquitous on CP1400s 220 */ 221 char val[32]; 222 prom_getproperty(prom_root_node, "model", val, sizeof(val)); 223 return((!strcmp(val, WD_BADMODEL)) ? 1 : 0); 224} 225 226/* Retrieve watchdog-enable? option from OBP 227 * Returns 0 if false, 1 if true 228 */ 229static inline int wd_opt_enable(void) 230{ 231 int opt_node; 232 233 opt_node = prom_getchild(prom_root_node); 234 opt_node = prom_searchsiblings(opt_node, "options"); 235 return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1); 236} 237 238/* Retrieve watchdog-reboot? option from OBP 239 * Returns 0 if false, 1 if true 240 */ 241static inline int wd_opt_reboot(void) 242{ 243 int opt_node; 244 245 opt_node = prom_getchild(prom_root_node); 246 opt_node = prom_searchsiblings(opt_node, "options"); 247 return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1); 248} 249 250/* Retrieve watchdog-timeout option from OBP 251 * Returns OBP value, or 0 if not located 252 */ 253static inline int wd_opt_timeout(void) 254{ 255 int opt_node; 256 char value[32]; 257 char *p = value; 258 259 opt_node = prom_getchild(prom_root_node); 260 opt_node = prom_searchsiblings(opt_node, "options"); 261 opt_node = prom_getproperty(opt_node, 262 "watchdog-timeout", 263 value, 264 sizeof(value)); 265 if(-1 != opt_node) { 266 /* atoi implementation */ 267 for(opt_node = 0; /* nop */; p++) { 268 if(*p >= '0' && *p <= '9') { 269 opt_node = (10*opt_node)+(*p-'0'); 270 } 271 else { 272 break; 273 } 274 } 275 } 276 return((-1 == opt_node) ? (0) : (opt_node)); 277} 278 279static int wd_open(struct inode *inode, struct file *f) 280{ 281 switch(iminor(inode)) 282 { 283 case WD0_MINOR: 284 f->private_data = &wd_dev.watchdog[WD0_ID]; 285 break; 286 case WD1_MINOR: 287 f->private_data = &wd_dev.watchdog[WD1_ID]; 288 break; 289 case WD2_MINOR: 290 f->private_data = &wd_dev.watchdog[WD2_ID]; 291 break; 292 default: 293 return(-ENODEV); 294 } 295 296 /* Register IRQ on first open of device */ 297 if(0 == wd_dev.initialized) 298 { 299 if (request_irq(wd_dev.irq, 300 &wd_interrupt, 301 IRQF_SHARED, 302 WD_OBPNAME, 303 (void *)wd_dev.regs)) { 304 printk("%s: Cannot register IRQ %d\n", 305 WD_OBPNAME, wd_dev.irq); 306 return(-EBUSY); 307 } 308 wd_dev.initialized = 1; 309 } 310 311 return(nonseekable_open(inode, f)); 312} 313 314static int wd_release(struct inode *inode, struct file *file) 315{ 316 return 0; 317} 318 319static int wd_ioctl(struct inode *inode, struct file *file, 320 unsigned int cmd, unsigned long arg) 321{ 322 int setopt = 0; 323 struct wd_timer* pTimer = (struct wd_timer*)file->private_data; 324 void __user *argp = (void __user *)arg; 325 struct watchdog_info info = { 326 0, 327 0, 328 "Altera EPF8820ATC144-4" 329 }; 330 331 if(NULL == pTimer) { 332 return(-EINVAL); 333 } 334 335 switch(cmd) 336 { 337 /* Generic Linux IOCTLs */ 338 case WDIOC_GETSUPPORT: 339 if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) { 340 return(-EFAULT); 341 } 342 break; 343 case WDIOC_GETSTATUS: 344 case WDIOC_GETBOOTSTATUS: 345 if (put_user(0, (int __user *)argp)) 346 return -EFAULT; 347 break; 348 case WDIOC_KEEPALIVE: 349 wd_pingtimer(pTimer); 350 break; 351 case WDIOC_SETOPTIONS: 352 if(copy_from_user(&setopt, argp, sizeof(unsigned int))) { 353 return -EFAULT; 354 } 355 if(setopt & WDIOS_DISABLECARD) { 356 if(wd_dev.opt_enable) { 357 printk( 358 "%s: cannot disable watchdog in ENABLED mode\n", 359 WD_OBPNAME); 360 return(-EINVAL); 361 } 362 wd_stoptimer(pTimer); 363 } 364 else if(setopt & WDIOS_ENABLECARD) { 365 wd_starttimer(pTimer); 366 } 367 else { 368 return(-EINVAL); 369 } 370 break; 371 /* Solaris-compatible IOCTLs */ 372 case WIOCGSTAT: 373 setopt = wd_getstatus(pTimer); 374 if(copy_to_user(argp, &setopt, sizeof(unsigned int))) { 375 return(-EFAULT); 376 } 377 break; 378 case WIOCSTART: 379 wd_starttimer(pTimer); 380 break; 381 case WIOCSTOP: 382 if(wd_dev.opt_enable) { 383 printk("%s: cannot disable watchdog in ENABLED mode\n", 384 WD_OBPNAME); 385 return(-EINVAL); 386 } 387 wd_stoptimer(pTimer); 388 break; 389 default: 390 return(-EINVAL); 391 } 392 return(0); 393} 394 395static long wd_compat_ioctl(struct file *file, unsigned int cmd, 396 unsigned long arg) 397{ 398 int rval = -ENOIOCTLCMD; 399 400 switch (cmd) { 401 /* solaris ioctls are specific to this driver */ 402 case WIOCSTART: 403 case WIOCSTOP: 404 case WIOCGSTAT: 405 lock_kernel(); 406 rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); 407 unlock_kernel(); 408 break; 409 /* everything else is handled by the generic compat layer */ 410 default: 411 break; 412 } 413 414 return rval; 415} 416 417static ssize_t wd_write(struct file *file, 418 const char __user *buf, 419 size_t count, 420 loff_t *ppos) 421{ 422 struct wd_timer* pTimer = (struct wd_timer*)file->private_data; 423 424 if(NULL == pTimer) { 425 return(-EINVAL); 426 } 427 428 if (count) { 429 wd_pingtimer(pTimer); 430 return 1; 431 } 432 return 0; 433} 434 435static ssize_t wd_read(struct file * file, char __user *buffer, 436 size_t count, loff_t *ppos) 437{ 438#ifdef WD_DEBUG 439 wd_dumpregs(); 440 return(0); 441#else 442 return(-EINVAL); 443#endif /* ifdef WD_DEBUG */ 444} 445 446static irqreturn_t wd_interrupt(int irq, void *dev_id) 447{ 448 /* Only WD0 will interrupt-- others are NMI and we won't 449 * see them here.... 450 */ 451 spin_lock_irq(&wd_dev.lock); 452 if((unsigned long)wd_dev.regs == (unsigned long)dev_id) 453 { 454 wd_stoptimer(&wd_dev.watchdog[WD0_ID]); 455 wd_dev.watchdog[WD0_ID].runstatus |= WD_STAT_SVCD; 456 } 457 spin_unlock_irq(&wd_dev.lock); 458 return IRQ_HANDLED; 459} 460 461static const struct file_operations wd_fops = { 462 .owner = THIS_MODULE, 463 .ioctl = wd_ioctl, 464 .compat_ioctl = wd_compat_ioctl, 465 .open = wd_open, 466 .write = wd_write, 467 .read = wd_read, 468 .release = wd_release, 469}; 470 471static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops }; 472static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops }; 473static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops }; 474 475#ifdef WD_DEBUG 476static void wd_dumpregs(void) 477{ 478 /* Reading from downcounters initiates watchdog countdown-- 479 * Example is included below for illustration purposes. 480 */ 481 int i; 482 printk("%s: dumping register values\n", WD_OBPNAME); 483 for(i = WD0_ID; i < WD_NUMDEVS; ++i) { 484 /* printk("\t%s%i: dcntr at 0x%lx: 0x%x\n", 485 * WD_OBPNAME, 486 * i, 487 * (unsigned long)(&wd_dev.watchdog[i].regs->dcntr), 488 * readw(&wd_dev.watchdog[i].regs->dcntr)); 489 */ 490 printk("\t%s%i: limit at 0x%lx: 0x%x\n", 491 WD_OBPNAME, 492 i, 493 (unsigned long)(&wd_dev.watchdog[i].regs->limit), 494 readw(&wd_dev.watchdog[i].regs->limit)); 495 printk("\t%s%i: status at 0x%lx: 0x%x\n", 496 WD_OBPNAME, 497 i, 498 (unsigned long)(&wd_dev.watchdog[i].regs->status), 499 readb(&wd_dev.watchdog[i].regs->status)); 500 printk("\t%s%i: driver status: 0x%x\n", 501 WD_OBPNAME, 502 i, 503 wd_getstatus(&wd_dev.watchdog[i])); 504 } 505 printk("\tintr_mask at %p: 0x%x\n", 506 wd_dev.regs + PLD_IMASK, 507 readb(wd_dev.regs + PLD_IMASK)); 508 printk("\tpld_status at %p: 0x%x\n", 509 wd_dev.regs + PLD_STATUS, 510 readb(wd_dev.regs + PLD_STATUS)); 511} 512#endif 513 514/* Enable or disable watchdog interrupts 515 * Because of the CP1400 defect this should only be 516 * called during initialzation or by wd_[start|stop]timer() 517 * 518 * pTimer - pointer to timer device, or NULL to indicate all timers 519 * enable - non-zero to enable interrupts, zero to disable 520 */ 521static void wd_toggleintr(struct wd_timer* pTimer, int enable) 522{ 523 unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK); 524 unsigned char setregs = 525 (NULL == pTimer) ? 526 (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : 527 (pTimer->intr_mask); 528 529 (WD_INTR_ON == enable) ? 530 (curregs &= ~setregs): 531 (curregs |= setregs); 532 533 wd_writeb(curregs, wd_dev.regs + PLD_IMASK); 534 return; 535} 536 537/* Reset countdown timer with 'limit' value and continue countdown. 538 * This will not start a stopped timer. 539 * 540 * pTimer - pointer to timer device 541 */ 542static void wd_pingtimer(struct wd_timer* pTimer) 543{ 544 if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { 545 wd_readw(pTimer->regs + WD_DCNTR); 546 } 547} 548 549/* Stop a running watchdog timer-- the timer actually keeps 550 * running, but the interrupt is masked so that no action is 551 * taken upon expiration. 552 * 553 * pTimer - pointer to timer device 554 */ 555static void wd_stoptimer(struct wd_timer* pTimer) 556{ 557 if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { 558 wd_toggleintr(pTimer, WD_INTR_OFF); 559 560 if(wd_dev.isbaddoggie) { 561 pTimer->runstatus |= WD_STAT_BSTOP; 562 wd_brokentimer((unsigned long)&wd_dev); 563 } 564 } 565} 566 567/* Start a watchdog timer with the specified limit value 568 * If the watchdog is running, it will be restarted with 569 * the provided limit value. 570 * 571 * This function will enable interrupts on the specified 572 * watchdog. 573 * 574 * pTimer - pointer to timer device 575 * limit - limit (countdown) value in 1/10th seconds 576 */ 577static void wd_starttimer(struct wd_timer* pTimer) 578{ 579 if(wd_dev.isbaddoggie) { 580 pTimer->runstatus &= ~WD_STAT_BSTOP; 581 } 582 pTimer->runstatus &= ~WD_STAT_SVCD; 583 584 wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT); 585 wd_toggleintr(pTimer, WD_INTR_ON); 586} 587 588/* Restarts timer with maximum limit value and 589 * does not unset 'brokenstop' value. 590 */ 591static void wd_resetbrokentimer(struct wd_timer* pTimer) 592{ 593 wd_toggleintr(pTimer, WD_INTR_ON); 594 wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT); 595} 596 597/* Timer device initialization helper. 598 * Returns 0 on success, other on failure 599 */ 600static int wd_inittimer(int whichdog) 601{ 602 struct miscdevice *whichmisc; 603 void __iomem *whichregs; 604 char whichident[8]; 605 int whichmask; 606 __u16 whichlimit; 607 608 switch(whichdog) 609 { 610 case WD0_ID: 611 whichmisc = &wd0_miscdev; 612 strcpy(whichident, "RIC"); 613 whichregs = wd_dev.regs + WD0_OFF; 614 whichmask = WD0_INTR_MASK; 615 whichlimit= (0 == wd0_timeout) ? 616 (wd_dev.opt_timeout): 617 (wd0_timeout); 618 break; 619 case WD1_ID: 620 whichmisc = &wd1_miscdev; 621 strcpy(whichident, "XIR"); 622 whichregs = wd_dev.regs + WD1_OFF; 623 whichmask = WD1_INTR_MASK; 624 whichlimit= (0 == wd1_timeout) ? 625 (wd_dev.opt_timeout): 626 (wd1_timeout); 627 break; 628 case WD2_ID: 629 whichmisc = &wd2_miscdev; 630 strcpy(whichident, "POR"); 631 whichregs = wd_dev.regs + WD2_OFF; 632 whichmask = WD2_INTR_MASK; 633 whichlimit= (0 == wd2_timeout) ? 634 (wd_dev.opt_timeout): 635 (wd2_timeout); 636 break; 637 default: 638 printk("%s: %s: invalid watchdog id: %i\n", 639 WD_OBPNAME, __FUNCTION__, whichdog); 640 return(1); 641 } 642 if(0 != misc_register(whichmisc)) 643 { 644 return(1); 645 } 646 wd_dev.watchdog[whichdog].regs = whichregs; 647 wd_dev.watchdog[whichdog].timeout = whichlimit; 648 wd_dev.watchdog[whichdog].intr_mask = whichmask; 649 wd_dev.watchdog[whichdog].runstatus &= ~WD_STAT_BSTOP; 650 wd_dev.watchdog[whichdog].runstatus |= WD_STAT_INIT; 651 652 printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", 653 WD_OBPNAME, 654 whichdog, 655 whichident, 656 wd_dev.watchdog[whichdog].timeout / 10, 657 wd_dev.watchdog[whichdog].timeout % 10, 658 (0 != wd_dev.opt_enable) ? "in ENABLED mode" : ""); 659 return(0); 660} 661 662/* Timer method called to reset stopped watchdogs-- 663 * because of the PLD bug on CP1400, we cannot mask 664 * interrupts within the PLD so me must continually 665 * reset the timers ad infinitum. 666 */ 667static void wd_brokentimer(unsigned long data) 668{ 669 struct wd_device* pDev = (struct wd_device*)data; 670 int id, tripped = 0; 671 672 /* kill a running timer instance, in case we 673 * were called directly instead of by kernel timer 674 */ 675 if(timer_pending(&wd_timer)) { 676 del_timer(&wd_timer); 677 } 678 679 for(id = WD0_ID; id < WD_NUMDEVS; ++id) { 680 if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) { 681 ++tripped; 682 wd_resetbrokentimer(&pDev->watchdog[id]); 683 } 684 } 685 686 if(tripped) { 687 /* there is at least one timer brokenstopped-- reschedule */ 688 init_timer(&wd_timer); 689 wd_timer.expires = WD_BTIMEOUT; 690 add_timer(&wd_timer); 691 } 692} 693 694static int wd_getstatus(struct wd_timer* pTimer) 695{ 696 unsigned char stat = wd_readb(pTimer->regs + WD_STATUS); 697 unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK); 698 unsigned char ret = WD_STOPPED; 699 700 /* determine STOPPED */ 701 if(0 == stat ) { 702 return(ret); 703 } 704 /* determine EXPIRED vs FREERUN vs RUNNING */ 705 else if(WD_S_EXPIRED & stat) { 706 ret = WD_EXPIRED; 707 } 708 else if(WD_S_RUNNING & stat) { 709 if(intr & pTimer->intr_mask) { 710 ret = WD_FREERUN; 711 } 712 else { 713 /* Fudge WD_EXPIRED status for defective CP1400-- 714 * IF timer is running 715 * AND brokenstop is set 716 * AND an interrupt has been serviced 717 * we are WD_EXPIRED. 718 * 719 * IF timer is running 720 * AND brokenstop is set 721 * AND no interrupt has been serviced 722 * we are WD_FREERUN. 723 */ 724 if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) { 725 if(pTimer->runstatus & WD_STAT_SVCD) { 726 ret = WD_EXPIRED; 727 } 728 else { 729 /* we could as well pretend we are expired */ 730 ret = WD_FREERUN; 731 } 732 } 733 else { 734 ret = WD_RUNNING; 735 } 736 } 737 } 738 739 /* determine SERVICED */ 740 if(pTimer->runstatus & WD_STAT_SVCD) { 741 ret |= WD_SERVICED; 742 } 743 744 return(ret); 745} 746 747static int __init wd_init(void) 748{ 749 int id; 750 struct linux_ebus *ebus = NULL; 751 struct linux_ebus_device *edev = NULL; 752 753 for_each_ebus(ebus) { 754 for_each_ebusdev(edev, ebus) { 755 if (!strcmp(edev->ofdev.node->name, WD_OBPNAME)) 756 goto ebus_done; 757 } 758 } 759 760ebus_done: 761 if(!edev) { 762 printk("%s: unable to locate device\n", WD_OBPNAME); 763 return -ENODEV; 764 } 765 766 wd_dev.regs = 767 ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */ 768 769 if(NULL == wd_dev.regs) { 770 printk("%s: unable to map registers\n", WD_OBPNAME); 771 return(-ENODEV); 772 } 773 774 /* initialize device structure from OBP parameters */ 775 wd_dev.irq = edev->irqs[0]; 776 wd_dev.opt_enable = wd_opt_enable(); 777 wd_dev.opt_reboot = wd_opt_reboot(); 778 wd_dev.opt_timeout = wd_opt_timeout(); 779 wd_dev.isbaddoggie = wd_isbroken(); 780 781 /* disable all interrupts unless watchdog-enabled? == true */ 782 if(! wd_dev.opt_enable) { 783 wd_toggleintr(NULL, WD_INTR_OFF); 784 } 785 786 /* register miscellaneous devices */ 787 for(id = WD0_ID; id < WD_NUMDEVS; ++id) { 788 if(0 != wd_inittimer(id)) { 789 printk("%s%i: unable to initialize\n", WD_OBPNAME, id); 790 } 791 } 792 793 /* warn about possible defective PLD */ 794 if(wd_dev.isbaddoggie) { 795 init_timer(&wd_timer); 796 wd_timer.function = wd_brokentimer; 797 wd_timer.data = (unsigned long)&wd_dev; 798 wd_timer.expires = WD_BTIMEOUT; 799 800 printk("%s: PLD defect workaround enabled for model %s\n", 801 WD_OBPNAME, WD_BADMODEL); 802 } 803 return(0); 804} 805 806static void __exit wd_cleanup(void) 807{ 808 int id; 809 810 /* if 'watchdog-enable?' == TRUE, timers are not stopped 811 * when module is unloaded. All brokenstopped timers will 812 * also now eventually trip. 813 */ 814 for(id = WD0_ID; id < WD_NUMDEVS; ++id) { 815 if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) { 816 if(wd_dev.opt_enable) { 817 printk(KERN_WARNING "%s%i: timer not stopped at release\n", 818 WD_OBPNAME, id); 819 } 820 else { 821 wd_stoptimer(&wd_dev.watchdog[id]); 822 if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) { 823 wd_resetbrokentimer(&wd_dev.watchdog[id]); 824 printk(KERN_WARNING 825 "%s%i: defect workaround disabled at release, "\ 826 "timer expires in ~%01i sec\n", 827 WD_OBPNAME, id, 828 wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10); 829 } 830 } 831 } 832 } 833 834 if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) { 835 del_timer(&wd_timer); 836 } 837 if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) { 838 misc_deregister(&wd0_miscdev); 839 } 840 if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) { 841 misc_deregister(&wd1_miscdev); 842 } 843 if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) { 844 misc_deregister(&wd2_miscdev); 845 } 846 if(0 != wd_dev.initialized) { 847 free_irq(wd_dev.irq, (void *)wd_dev.regs); 848 } 849 iounmap(wd_dev.regs); 850} 851 852module_init(wd_init); 853module_exit(wd_cleanup); 854