cpwatchdog.c 21 KB

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