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