cpwatchdog.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  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(wd_dev.lock), 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. lock_kernel();
  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. unlock_kernel();
  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. IRQF_SHARED,
  271. WD_OBPNAME,
  272. (void *)wd_dev.regs)) {
  273. printk("%s: Cannot register IRQ %d\n",
  274. WD_OBPNAME, wd_dev.irq);
  275. unlock_kernel();
  276. return(-EBUSY);
  277. }
  278. wd_dev.initialized = 1;
  279. }
  280. unlock_kernel();
  281. return(nonseekable_open(inode, f));
  282. }
  283. static int wd_release(struct inode *inode, struct file *file)
  284. {
  285. return 0;
  286. }
  287. static int wd_ioctl(struct inode *inode, struct file *file,
  288. unsigned int cmd, unsigned long arg)
  289. {
  290. int setopt = 0;
  291. struct wd_timer* pTimer = (struct wd_timer*)file->private_data;
  292. void __user *argp = (void __user *)arg;
  293. struct watchdog_info info = {
  294. 0,
  295. 0,
  296. "Altera EPF8820ATC144-4"
  297. };
  298. if(NULL == pTimer) {
  299. return(-EINVAL);
  300. }
  301. switch(cmd)
  302. {
  303. /* Generic Linux IOCTLs */
  304. case WDIOC_GETSUPPORT:
  305. if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) {
  306. return(-EFAULT);
  307. }
  308. break;
  309. case WDIOC_GETSTATUS:
  310. case WDIOC_GETBOOTSTATUS:
  311. if (put_user(0, (int __user *)argp))
  312. return -EFAULT;
  313. break;
  314. case WDIOC_KEEPALIVE:
  315. wd_pingtimer(pTimer);
  316. break;
  317. case WDIOC_SETOPTIONS:
  318. if(copy_from_user(&setopt, argp, sizeof(unsigned int))) {
  319. return -EFAULT;
  320. }
  321. if(setopt & WDIOS_DISABLECARD) {
  322. if(wd_dev.opt_enable) {
  323. printk(
  324. "%s: cannot disable watchdog in ENABLED mode\n",
  325. WD_OBPNAME);
  326. return(-EINVAL);
  327. }
  328. wd_stoptimer(pTimer);
  329. }
  330. else if(setopt & WDIOS_ENABLECARD) {
  331. wd_starttimer(pTimer);
  332. }
  333. else {
  334. return(-EINVAL);
  335. }
  336. break;
  337. /* Solaris-compatible IOCTLs */
  338. case WIOCGSTAT:
  339. setopt = wd_getstatus(pTimer);
  340. if(copy_to_user(argp, &setopt, sizeof(unsigned int))) {
  341. return(-EFAULT);
  342. }
  343. break;
  344. case WIOCSTART:
  345. wd_starttimer(pTimer);
  346. break;
  347. case WIOCSTOP:
  348. if(wd_dev.opt_enable) {
  349. printk("%s: cannot disable watchdog in ENABLED mode\n",
  350. WD_OBPNAME);
  351. return(-EINVAL);
  352. }
  353. wd_stoptimer(pTimer);
  354. break;
  355. default:
  356. return(-EINVAL);
  357. }
  358. return(0);
  359. }
  360. static long wd_compat_ioctl(struct file *file, unsigned int cmd,
  361. unsigned long arg)
  362. {
  363. int rval = -ENOIOCTLCMD;
  364. switch (cmd) {
  365. /* solaris ioctls are specific to this driver */
  366. case WIOCSTART:
  367. case WIOCSTOP:
  368. case WIOCGSTAT:
  369. lock_kernel();
  370. rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
  371. unlock_kernel();
  372. break;
  373. /* everything else is handled by the generic compat layer */
  374. default:
  375. break;
  376. }
  377. return rval;
  378. }
  379. static ssize_t wd_write(struct file *file,
  380. const char __user *buf,
  381. size_t count,
  382. loff_t *ppos)
  383. {
  384. struct wd_timer* pTimer = (struct wd_timer*)file->private_data;
  385. if(NULL == pTimer) {
  386. return(-EINVAL);
  387. }
  388. if (count) {
  389. wd_pingtimer(pTimer);
  390. return 1;
  391. }
  392. return 0;
  393. }
  394. static ssize_t wd_read(struct file * file, char __user *buffer,
  395. size_t count, loff_t *ppos)
  396. {
  397. #ifdef WD_DEBUG
  398. wd_dumpregs();
  399. return(0);
  400. #else
  401. return(-EINVAL);
  402. #endif /* ifdef WD_DEBUG */
  403. }
  404. static irqreturn_t wd_interrupt(int irq, void *dev_id)
  405. {
  406. /* Only WD0 will interrupt-- others are NMI and we won't
  407. * see them here....
  408. */
  409. spin_lock_irq(&wd_dev.lock);
  410. if((unsigned long)wd_dev.regs == (unsigned long)dev_id)
  411. {
  412. wd_stoptimer(&wd_dev.watchdog[WD0_ID]);
  413. wd_dev.watchdog[WD0_ID].runstatus |= WD_STAT_SVCD;
  414. }
  415. spin_unlock_irq(&wd_dev.lock);
  416. return IRQ_HANDLED;
  417. }
  418. static const struct file_operations wd_fops = {
  419. .owner = THIS_MODULE,
  420. .ioctl = wd_ioctl,
  421. .compat_ioctl = wd_compat_ioctl,
  422. .open = wd_open,
  423. .write = wd_write,
  424. .read = wd_read,
  425. .release = wd_release,
  426. };
  427. static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops };
  428. static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops };
  429. static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops };
  430. #ifdef WD_DEBUG
  431. static void wd_dumpregs(void)
  432. {
  433. /* Reading from downcounters initiates watchdog countdown--
  434. * Example is included below for illustration purposes.
  435. */
  436. int i;
  437. printk("%s: dumping register values\n", WD_OBPNAME);
  438. for(i = WD0_ID; i < WD_NUMDEVS; ++i) {
  439. /* printk("\t%s%i: dcntr at 0x%lx: 0x%x\n",
  440. * WD_OBPNAME,
  441. * i,
  442. * (unsigned long)(&wd_dev.watchdog[i].regs->dcntr),
  443. * readw(&wd_dev.watchdog[i].regs->dcntr));
  444. */
  445. printk("\t%s%i: limit at 0x%lx: 0x%x\n",
  446. WD_OBPNAME,
  447. i,
  448. (unsigned long)(&wd_dev.watchdog[i].regs->limit),
  449. readw(&wd_dev.watchdog[i].regs->limit));
  450. printk("\t%s%i: status at 0x%lx: 0x%x\n",
  451. WD_OBPNAME,
  452. i,
  453. (unsigned long)(&wd_dev.watchdog[i].regs->status),
  454. readb(&wd_dev.watchdog[i].regs->status));
  455. printk("\t%s%i: driver status: 0x%x\n",
  456. WD_OBPNAME,
  457. i,
  458. wd_getstatus(&wd_dev.watchdog[i]));
  459. }
  460. printk("\tintr_mask at %p: 0x%x\n",
  461. wd_dev.regs + PLD_IMASK,
  462. readb(wd_dev.regs + PLD_IMASK));
  463. printk("\tpld_status at %p: 0x%x\n",
  464. wd_dev.regs + PLD_STATUS,
  465. readb(wd_dev.regs + PLD_STATUS));
  466. }
  467. #endif
  468. /* Enable or disable watchdog interrupts
  469. * Because of the CP1400 defect this should only be
  470. * called during initialzation or by wd_[start|stop]timer()
  471. *
  472. * pTimer - pointer to timer device, or NULL to indicate all timers
  473. * enable - non-zero to enable interrupts, zero to disable
  474. */
  475. static void wd_toggleintr(struct wd_timer* pTimer, int enable)
  476. {
  477. unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK);
  478. unsigned char setregs =
  479. (NULL == pTimer) ?
  480. (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) :
  481. (pTimer->intr_mask);
  482. (WD_INTR_ON == enable) ?
  483. (curregs &= ~setregs):
  484. (curregs |= setregs);
  485. wd_writeb(curregs, wd_dev.regs + PLD_IMASK);
  486. return;
  487. }
  488. /* Reset countdown timer with 'limit' value and continue countdown.
  489. * This will not start a stopped timer.
  490. *
  491. * pTimer - pointer to timer device
  492. */
  493. static void wd_pingtimer(struct wd_timer* pTimer)
  494. {
  495. if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
  496. wd_readw(pTimer->regs + WD_DCNTR);
  497. }
  498. }
  499. /* Stop a running watchdog timer-- the timer actually keeps
  500. * running, but the interrupt is masked so that no action is
  501. * taken upon expiration.
  502. *
  503. * pTimer - pointer to timer device
  504. */
  505. static void wd_stoptimer(struct wd_timer* pTimer)
  506. {
  507. if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
  508. wd_toggleintr(pTimer, WD_INTR_OFF);
  509. if(wd_dev.isbaddoggie) {
  510. pTimer->runstatus |= WD_STAT_BSTOP;
  511. wd_brokentimer((unsigned long)&wd_dev);
  512. }
  513. }
  514. }
  515. /* Start a watchdog timer with the specified limit value
  516. * If the watchdog is running, it will be restarted with
  517. * the provided limit value.
  518. *
  519. * This function will enable interrupts on the specified
  520. * watchdog.
  521. *
  522. * pTimer - pointer to timer device
  523. * limit - limit (countdown) value in 1/10th seconds
  524. */
  525. static void wd_starttimer(struct wd_timer* pTimer)
  526. {
  527. if(wd_dev.isbaddoggie) {
  528. pTimer->runstatus &= ~WD_STAT_BSTOP;
  529. }
  530. pTimer->runstatus &= ~WD_STAT_SVCD;
  531. wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT);
  532. wd_toggleintr(pTimer, WD_INTR_ON);
  533. }
  534. /* Restarts timer with maximum limit value and
  535. * does not unset 'brokenstop' value.
  536. */
  537. static void wd_resetbrokentimer(struct wd_timer* pTimer)
  538. {
  539. wd_toggleintr(pTimer, WD_INTR_ON);
  540. wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT);
  541. }
  542. /* Timer device initialization helper.
  543. * Returns 0 on success, other on failure
  544. */
  545. static int wd_inittimer(int whichdog)
  546. {
  547. struct miscdevice *whichmisc;
  548. void __iomem *whichregs;
  549. char whichident[8];
  550. int whichmask;
  551. __u16 whichlimit;
  552. switch(whichdog)
  553. {
  554. case WD0_ID:
  555. whichmisc = &wd0_miscdev;
  556. strcpy(whichident, "RIC");
  557. whichregs = wd_dev.regs + WD0_OFF;
  558. whichmask = WD0_INTR_MASK;
  559. whichlimit= (0 == wd0_timeout) ?
  560. (wd_dev.opt_timeout):
  561. (wd0_timeout);
  562. break;
  563. case WD1_ID:
  564. whichmisc = &wd1_miscdev;
  565. strcpy(whichident, "XIR");
  566. whichregs = wd_dev.regs + WD1_OFF;
  567. whichmask = WD1_INTR_MASK;
  568. whichlimit= (0 == wd1_timeout) ?
  569. (wd_dev.opt_timeout):
  570. (wd1_timeout);
  571. break;
  572. case WD2_ID:
  573. whichmisc = &wd2_miscdev;
  574. strcpy(whichident, "POR");
  575. whichregs = wd_dev.regs + WD2_OFF;
  576. whichmask = WD2_INTR_MASK;
  577. whichlimit= (0 == wd2_timeout) ?
  578. (wd_dev.opt_timeout):
  579. (wd2_timeout);
  580. break;
  581. default:
  582. printk("%s: %s: invalid watchdog id: %i\n",
  583. WD_OBPNAME, __func__, whichdog);
  584. return(1);
  585. }
  586. if(0 != misc_register(whichmisc))
  587. {
  588. return(1);
  589. }
  590. wd_dev.watchdog[whichdog].regs = whichregs;
  591. wd_dev.watchdog[whichdog].timeout = whichlimit;
  592. wd_dev.watchdog[whichdog].intr_mask = whichmask;
  593. wd_dev.watchdog[whichdog].runstatus &= ~WD_STAT_BSTOP;
  594. wd_dev.watchdog[whichdog].runstatus |= WD_STAT_INIT;
  595. printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n",
  596. WD_OBPNAME,
  597. whichdog,
  598. whichident,
  599. wd_dev.watchdog[whichdog].timeout / 10,
  600. wd_dev.watchdog[whichdog].timeout % 10,
  601. (0 != wd_dev.opt_enable) ? "in ENABLED mode" : "");
  602. return(0);
  603. }
  604. /* Timer method called to reset stopped watchdogs--
  605. * because of the PLD bug on CP1400, we cannot mask
  606. * interrupts within the PLD so me must continually
  607. * reset the timers ad infinitum.
  608. */
  609. static void wd_brokentimer(unsigned long data)
  610. {
  611. struct wd_device* pDev = (struct wd_device*)data;
  612. int id, tripped = 0;
  613. /* kill a running timer instance, in case we
  614. * were called directly instead of by kernel timer
  615. */
  616. if(timer_pending(&wd_timer)) {
  617. del_timer(&wd_timer);
  618. }
  619. for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
  620. if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) {
  621. ++tripped;
  622. wd_resetbrokentimer(&pDev->watchdog[id]);
  623. }
  624. }
  625. if(tripped) {
  626. /* there is at least one timer brokenstopped-- reschedule */
  627. init_timer(&wd_timer);
  628. wd_timer.expires = WD_BTIMEOUT;
  629. add_timer(&wd_timer);
  630. }
  631. }
  632. static int wd_getstatus(struct wd_timer* pTimer)
  633. {
  634. unsigned char stat = wd_readb(pTimer->regs + WD_STATUS);
  635. unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK);
  636. unsigned char ret = WD_STOPPED;
  637. /* determine STOPPED */
  638. if(0 == stat ) {
  639. return(ret);
  640. }
  641. /* determine EXPIRED vs FREERUN vs RUNNING */
  642. else if(WD_S_EXPIRED & stat) {
  643. ret = WD_EXPIRED;
  644. }
  645. else if(WD_S_RUNNING & stat) {
  646. if(intr & pTimer->intr_mask) {
  647. ret = WD_FREERUN;
  648. }
  649. else {
  650. /* Fudge WD_EXPIRED status for defective CP1400--
  651. * IF timer is running
  652. * AND brokenstop is set
  653. * AND an interrupt has been serviced
  654. * we are WD_EXPIRED.
  655. *
  656. * IF timer is running
  657. * AND brokenstop is set
  658. * AND no interrupt has been serviced
  659. * we are WD_FREERUN.
  660. */
  661. if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) {
  662. if(pTimer->runstatus & WD_STAT_SVCD) {
  663. ret = WD_EXPIRED;
  664. }
  665. else {
  666. /* we could as well pretend we are expired */
  667. ret = WD_FREERUN;
  668. }
  669. }
  670. else {
  671. ret = WD_RUNNING;
  672. }
  673. }
  674. }
  675. /* determine SERVICED */
  676. if(pTimer->runstatus & WD_STAT_SVCD) {
  677. ret |= WD_SERVICED;
  678. }
  679. return(ret);
  680. }
  681. static int __init wd_init(void)
  682. {
  683. int id;
  684. struct linux_ebus *ebus = NULL;
  685. struct linux_ebus_device *edev = NULL;
  686. for_each_ebus(ebus) {
  687. for_each_ebusdev(edev, ebus) {
  688. if (!strcmp(edev->ofdev.node->name, WD_OBPNAME))
  689. goto ebus_done;
  690. }
  691. }
  692. ebus_done:
  693. if(!edev) {
  694. printk("%s: unable to locate device\n", WD_OBPNAME);
  695. return -ENODEV;
  696. }
  697. wd_dev.regs =
  698. ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */
  699. if(NULL == wd_dev.regs) {
  700. printk("%s: unable to map registers\n", WD_OBPNAME);
  701. return(-ENODEV);
  702. }
  703. /* initialize device structure from OBP parameters */
  704. wd_dev.irq = edev->irqs[0];
  705. wd_dev.opt_enable = wd_opt_enable();
  706. wd_dev.opt_reboot = wd_opt_reboot();
  707. wd_dev.opt_timeout = wd_opt_timeout();
  708. wd_dev.isbaddoggie = wd_isbroken();
  709. /* disable all interrupts unless watchdog-enabled? == true */
  710. if(! wd_dev.opt_enable) {
  711. wd_toggleintr(NULL, WD_INTR_OFF);
  712. }
  713. /* register miscellaneous devices */
  714. for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
  715. if(0 != wd_inittimer(id)) {
  716. printk("%s%i: unable to initialize\n", WD_OBPNAME, id);
  717. }
  718. }
  719. /* warn about possible defective PLD */
  720. if(wd_dev.isbaddoggie) {
  721. init_timer(&wd_timer);
  722. wd_timer.function = wd_brokentimer;
  723. wd_timer.data = (unsigned long)&wd_dev;
  724. wd_timer.expires = WD_BTIMEOUT;
  725. printk("%s: PLD defect workaround enabled for model %s\n",
  726. WD_OBPNAME, WD_BADMODEL);
  727. }
  728. return(0);
  729. }
  730. static void __exit wd_cleanup(void)
  731. {
  732. int id;
  733. /* if 'watchdog-enable?' == TRUE, timers are not stopped
  734. * when module is unloaded. All brokenstopped timers will
  735. * also now eventually trip.
  736. */
  737. for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
  738. if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) {
  739. if(wd_dev.opt_enable) {
  740. printk(KERN_WARNING "%s%i: timer not stopped at release\n",
  741. WD_OBPNAME, id);
  742. }
  743. else {
  744. wd_stoptimer(&wd_dev.watchdog[id]);
  745. if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) {
  746. wd_resetbrokentimer(&wd_dev.watchdog[id]);
  747. printk(KERN_WARNING
  748. "%s%i: defect workaround disabled at release, "\
  749. "timer expires in ~%01i sec\n",
  750. WD_OBPNAME, id,
  751. wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10);
  752. }
  753. }
  754. }
  755. }
  756. if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) {
  757. del_timer(&wd_timer);
  758. }
  759. if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) {
  760. misc_deregister(&wd0_miscdev);
  761. }
  762. if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) {
  763. misc_deregister(&wd1_miscdev);
  764. }
  765. if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) {
  766. misc_deregister(&wd2_miscdev);
  767. }
  768. if(0 != wd_dev.initialized) {
  769. free_irq(wd_dev.irq, (void *)wd_dev.regs);
  770. }
  771. iounmap(wd_dev.regs);
  772. }
  773. module_init(wd_init);
  774. module_exit(wd_cleanup);