cpwatchdog.c 22 KB

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