cpwatchdog.c 21 KB

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