cpwatchdog.c 21 KB

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