pika_wdt.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * PIKA FPGA based Watchdog Timer
  3. *
  4. * Copyright (c) 2008 PIKA Technologies
  5. * Sean MacLennan <smaclennan@pikatech.com>
  6. */
  7. #include <linux/init.h>
  8. #include <linux/errno.h>
  9. #include <linux/module.h>
  10. #include <linux/moduleparam.h>
  11. #include <linux/types.h>
  12. #include <linux/kernel.h>
  13. #include <linux/fs.h>
  14. #include <linux/miscdevice.h>
  15. #include <linux/watchdog.h>
  16. #include <linux/reboot.h>
  17. #include <linux/jiffies.h>
  18. #include <linux/timer.h>
  19. #include <linux/bitops.h>
  20. #include <linux/uaccess.h>
  21. #include <linux/io.h>
  22. #include <linux/of_platform.h>
  23. #define DRV_NAME "PIKA-WDT"
  24. #define PFX DRV_NAME ": "
  25. /* Hardware timeout in seconds */
  26. #define WDT_HW_TIMEOUT 2
  27. /* Timer heartbeat (500ms) */
  28. #define WDT_TIMEOUT (HZ/2)
  29. /* User land timeout */
  30. #define WDT_HEARTBEAT 15
  31. static int heartbeat = WDT_HEARTBEAT;
  32. module_param(heartbeat, int, 0);
  33. MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
  34. "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
  35. static int nowayout = WATCHDOG_NOWAYOUT;
  36. module_param(nowayout, int, 0);
  37. MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
  38. "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  39. static struct {
  40. void __iomem *fpga;
  41. unsigned long next_heartbeat; /* the next_heartbeat for the timer */
  42. unsigned long open;
  43. char expect_close;
  44. int bootstatus;
  45. struct timer_list timer; /* The timer that pings the watchdog */
  46. } pikawdt_private;
  47. static struct watchdog_info ident = {
  48. .identity = DRV_NAME,
  49. .options = WDIOF_CARDRESET |
  50. WDIOF_SETTIMEOUT |
  51. WDIOF_KEEPALIVEPING |
  52. WDIOF_MAGICCLOSE,
  53. };
  54. /*
  55. * Reload the watchdog timer. (ie, pat the watchdog)
  56. */
  57. static inline void pikawdt_reset(void)
  58. {
  59. /* -- FPGA: Reset Control Register (32bit R/W) (Offset: 0x14) --
  60. * Bit 7, WTCHDG_EN: When set to 1, the watchdog timer is enabled.
  61. * Once enabled, it cannot be disabled. The watchdog can be
  62. * kicked by performing any write access to the reset
  63. * control register (this register).
  64. * Bit 8-11, WTCHDG_TIMEOUT_SEC: Sets the watchdog timeout value in
  65. * seconds. Valid ranges are 1 to 15 seconds. The value can
  66. * be modified dynamically.
  67. */
  68. unsigned reset = in_be32(pikawdt_private.fpga + 0x14);
  69. /* enable with max timeout - 15 seconds */
  70. reset |= (1 << 7) + (WDT_HW_TIMEOUT << 8);
  71. out_be32(pikawdt_private.fpga + 0x14, reset);
  72. }
  73. /*
  74. * Timer tick
  75. */
  76. static void pikawdt_ping(unsigned long data)
  77. {
  78. if (time_before(jiffies, pikawdt_private.next_heartbeat) ||
  79. (!nowayout && !pikawdt_private.open)) {
  80. pikawdt_reset();
  81. mod_timer(&pikawdt_private.timer, jiffies + WDT_TIMEOUT);
  82. } else
  83. printk(KERN_CRIT PFX "I will reset your machine !\n");
  84. }
  85. static void pikawdt_keepalive(void)
  86. {
  87. pikawdt_private.next_heartbeat = jiffies + heartbeat * HZ;
  88. }
  89. static void pikawdt_start(void)
  90. {
  91. pikawdt_keepalive();
  92. mod_timer(&pikawdt_private.timer, jiffies + WDT_TIMEOUT);
  93. }
  94. /*
  95. * Watchdog device is opened, and watchdog starts running.
  96. */
  97. static int pikawdt_open(struct inode *inode, struct file *file)
  98. {
  99. /* /dev/watchdog can only be opened once */
  100. if (test_and_set_bit(0, &pikawdt_private.open))
  101. return -EBUSY;
  102. pikawdt_start();
  103. return nonseekable_open(inode, file);
  104. }
  105. /*
  106. * Close the watchdog device.
  107. */
  108. static int pikawdt_release(struct inode *inode, struct file *file)
  109. {
  110. /* stop internal ping */
  111. if (!pikawdt_private.expect_close)
  112. del_timer(&pikawdt_private.timer);
  113. clear_bit(0, &pikawdt_private.open);
  114. pikawdt_private.expect_close = 0;
  115. return 0;
  116. }
  117. /*
  118. * Pat the watchdog whenever device is written to.
  119. */
  120. static ssize_t pikawdt_write(struct file *file, const char __user *data,
  121. size_t len, loff_t *ppos)
  122. {
  123. if (!len)
  124. return 0;
  125. /* Scan for magic character */
  126. if (!nowayout) {
  127. size_t i;
  128. pikawdt_private.expect_close = 0;
  129. for (i = 0; i < len; i++) {
  130. char c;
  131. if (get_user(c, data + i))
  132. return -EFAULT;
  133. if (c == 'V') {
  134. pikawdt_private.expect_close = 42;
  135. break;
  136. }
  137. }
  138. }
  139. pikawdt_keepalive();
  140. return len;
  141. }
  142. /*
  143. * Handle commands from user-space.
  144. */
  145. static long pikawdt_ioctl(struct file *file,
  146. unsigned int cmd, unsigned long arg)
  147. {
  148. void __user *argp = (void __user *)arg;
  149. int __user *p = argp;
  150. int new_value;
  151. switch (cmd) {
  152. case WDIOC_GETSUPPORT:
  153. return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
  154. case WDIOC_GETSTATUS:
  155. return put_user(0, p);
  156. case WDIOC_GETBOOTSTATUS:
  157. return put_user(pikawdt_private.bootstatus, p);
  158. case WDIOC_KEEPALIVE:
  159. pikawdt_keepalive();
  160. return 0;
  161. case WDIOC_SETTIMEOUT:
  162. if (get_user(new_value, p))
  163. return -EFAULT;
  164. heartbeat = new_value;
  165. pikawdt_keepalive();
  166. return put_user(new_value, p); /* return current value */
  167. case WDIOC_GETTIMEOUT:
  168. return put_user(heartbeat, p);
  169. }
  170. return -ENOTTY;
  171. }
  172. static const struct file_operations pikawdt_fops = {
  173. .owner = THIS_MODULE,
  174. .llseek = no_llseek,
  175. .open = pikawdt_open,
  176. .release = pikawdt_release,
  177. .write = pikawdt_write,
  178. .unlocked_ioctl = pikawdt_ioctl,
  179. };
  180. static struct miscdevice pikawdt_miscdev = {
  181. .minor = WATCHDOG_MINOR,
  182. .name = "watchdog",
  183. .fops = &pikawdt_fops,
  184. };
  185. static int __init pikawdt_init(void)
  186. {
  187. struct device_node *np;
  188. void __iomem *fpga;
  189. static u32 post1;
  190. int ret;
  191. np = of_find_compatible_node(NULL, NULL, "pika,fpga");
  192. if (np == NULL) {
  193. printk(KERN_ERR PFX "Unable to find fpga.\n");
  194. return -ENOENT;
  195. }
  196. pikawdt_private.fpga = of_iomap(np, 0);
  197. of_node_put(np);
  198. if (pikawdt_private.fpga == NULL) {
  199. printk(KERN_ERR PFX "Unable to map fpga.\n");
  200. return -ENOMEM;
  201. }
  202. ident.firmware_version = in_be32(pikawdt_private.fpga + 0x1c) & 0xffff;
  203. /* POST information is in the sd area. */
  204. np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd");
  205. if (np == NULL) {
  206. printk(KERN_ERR PFX "Unable to find fpga-sd.\n");
  207. ret = -ENOENT;
  208. goto out;
  209. }
  210. fpga = of_iomap(np, 0);
  211. of_node_put(np);
  212. if (fpga == NULL) {
  213. printk(KERN_ERR PFX "Unable to map fpga-sd.\n");
  214. ret = -ENOMEM;
  215. goto out;
  216. }
  217. /* -- FPGA: POST Test Results Register 1 (32bit R/W) (Offset: 0x4040) --
  218. * Bit 31, WDOG: Set to 1 when the last reset was caused by a watchdog
  219. * timeout.
  220. */
  221. post1 = in_be32(fpga + 0x40);
  222. if (post1 & 0x80000000)
  223. pikawdt_private.bootstatus = WDIOF_CARDRESET;
  224. iounmap(fpga);
  225. setup_timer(&pikawdt_private.timer, pikawdt_ping, 0);
  226. ret = misc_register(&pikawdt_miscdev);
  227. if (ret) {
  228. printk(KERN_ERR PFX "Unable to register miscdev.\n");
  229. goto out;
  230. }
  231. printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
  232. heartbeat, nowayout);
  233. return 0;
  234. out:
  235. iounmap(pikawdt_private.fpga);
  236. return ret;
  237. }
  238. static void __exit pikawdt_exit(void)
  239. {
  240. misc_deregister(&pikawdt_miscdev);
  241. iounmap(pikawdt_private.fpga);
  242. }
  243. module_init(pikawdt_init);
  244. module_exit(pikawdt_exit);
  245. MODULE_AUTHOR("Sean MacLennan <smaclennan@pikatech.com>");
  246. MODULE_DESCRIPTION("PIKA FPGA based Watchdog Timer");
  247. MODULE_LICENSE("GPL");
  248. MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);