0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0048
0049 #include <linux/module.h>
0050 #include <linux/io.h>
0051 #include <linux/uaccess.h>
0052 #include <linux/fs.h>
0053 #include <linux/reboot.h>
0054 #include <linux/miscdevice.h>
0055 #include <linux/watchdog.h>
0056 #include <linux/interrupt.h>
0057
0058 #include <asm/sibyte/sb1250.h>
0059 #include <asm/sibyte/sb1250_regs.h>
0060 #include <asm/sibyte/sb1250_int.h>
0061 #include <asm/sibyte/sb1250_scd.h>
0062
0063 static DEFINE_SPINLOCK(sbwd_lock);
0064
0065
0066
0067
0068
0069
0070 static void sbwdog_set(char __iomem *wdog, unsigned long t)
0071 {
0072 spin_lock(&sbwd_lock);
0073 __raw_writeb(0, wdog);
0074 __raw_writeq(t & 0x7fffffUL, wdog - 0x10);
0075 spin_unlock(&sbwd_lock);
0076 }
0077
0078
0079
0080
0081
0082
0083
0084 static void sbwdog_pet(char __iomem *wdog)
0085 {
0086 spin_lock(&sbwd_lock);
0087 __raw_writeb(__raw_readb(wdog) | 1, wdog);
0088 spin_unlock(&sbwd_lock);
0089 }
0090
0091 static unsigned long sbwdog_gate;
0092 static char __iomem *kern_dog = (char __iomem *)(IO_BASE + (A_SCD_WDOG_CFG_0));
0093 static char __iomem *user_dog = (char __iomem *)(IO_BASE + (A_SCD_WDOG_CFG_1));
0094 static unsigned long timeout = 0x7fffffUL;
0095 static int expect_close;
0096
0097 static const struct watchdog_info ident = {
0098 .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT |
0099 WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
0100 .identity = "SiByte Watchdog",
0101 };
0102
0103
0104
0105
0106 static int sbwdog_open(struct inode *inode, struct file *file)
0107 {
0108 stream_open(inode, file);
0109 if (test_and_set_bit(0, &sbwdog_gate))
0110 return -EBUSY;
0111 __module_get(THIS_MODULE);
0112
0113
0114
0115
0116 sbwdog_set(user_dog, timeout);
0117 __raw_writeb(1, user_dog);
0118
0119 return 0;
0120 }
0121
0122
0123
0124
0125 static int sbwdog_release(struct inode *inode, struct file *file)
0126 {
0127 if (expect_close == 42) {
0128 __raw_writeb(0, user_dog);
0129 module_put(THIS_MODULE);
0130 } else {
0131 pr_crit("%s: Unexpected close, not stopping watchdog!\n",
0132 ident.identity);
0133 sbwdog_pet(user_dog);
0134 }
0135 clear_bit(0, &sbwdog_gate);
0136 expect_close = 0;
0137
0138 return 0;
0139 }
0140
0141
0142
0143
0144 static ssize_t sbwdog_write(struct file *file, const char __user *data,
0145 size_t len, loff_t *ppos)
0146 {
0147 int i;
0148
0149 if (len) {
0150
0151
0152
0153 expect_close = 0;
0154
0155 for (i = 0; i != len; i++) {
0156 char c;
0157
0158 if (get_user(c, data + i))
0159 return -EFAULT;
0160 if (c == 'V')
0161 expect_close = 42;
0162 }
0163 sbwdog_pet(user_dog);
0164 }
0165
0166 return len;
0167 }
0168
0169 static long sbwdog_ioctl(struct file *file, unsigned int cmd,
0170 unsigned long arg)
0171 {
0172 int ret = -ENOTTY;
0173 unsigned long time;
0174 void __user *argp = (void __user *)arg;
0175 int __user *p = argp;
0176
0177 switch (cmd) {
0178 case WDIOC_GETSUPPORT:
0179 ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
0180 break;
0181
0182 case WDIOC_GETSTATUS:
0183 case WDIOC_GETBOOTSTATUS:
0184 ret = put_user(0, p);
0185 break;
0186
0187 case WDIOC_KEEPALIVE:
0188 sbwdog_pet(user_dog);
0189 ret = 0;
0190 break;
0191
0192 case WDIOC_SETTIMEOUT:
0193 ret = get_user(time, p);
0194 if (ret)
0195 break;
0196
0197 time *= 1000000;
0198 if (time > 0x7fffffUL) {
0199 ret = -EINVAL;
0200 break;
0201 }
0202 timeout = time;
0203 sbwdog_set(user_dog, timeout);
0204 sbwdog_pet(user_dog);
0205 fallthrough;
0206
0207 case WDIOC_GETTIMEOUT:
0208
0209
0210
0211
0212 ret = put_user((u32)__raw_readq(user_dog - 8) / 1000000, p);
0213 break;
0214 }
0215 return ret;
0216 }
0217
0218
0219
0220
0221 static int sbwdog_notify_sys(struct notifier_block *this, unsigned long code,
0222 void *erf)
0223 {
0224 if (code == SYS_DOWN || code == SYS_HALT) {
0225
0226
0227
0228 __raw_writeb(0, user_dog);
0229 __raw_writeb(0, kern_dog);
0230 }
0231
0232 return NOTIFY_DONE;
0233 }
0234
0235 static const struct file_operations sbwdog_fops = {
0236 .owner = THIS_MODULE,
0237 .llseek = no_llseek,
0238 .write = sbwdog_write,
0239 .unlocked_ioctl = sbwdog_ioctl,
0240 .compat_ioctl = compat_ptr_ioctl,
0241 .open = sbwdog_open,
0242 .release = sbwdog_release,
0243 };
0244
0245 static struct miscdevice sbwdog_miscdev = {
0246 .minor = WATCHDOG_MINOR,
0247 .name = "watchdog",
0248 .fops = &sbwdog_fops,
0249 };
0250
0251 static struct notifier_block sbwdog_notifier = {
0252 .notifier_call = sbwdog_notify_sys,
0253 };
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263 irqreturn_t sbwdog_interrupt(int irq, void *addr)
0264 {
0265 unsigned long wd_init;
0266 char *wd_cfg_reg = (char *)addr;
0267 u8 cfg;
0268
0269 cfg = __raw_readb(wd_cfg_reg);
0270 wd_init = __raw_readq(wd_cfg_reg - 8) & 0x7fffff;
0271
0272
0273
0274
0275 if (wd_cfg_reg == user_dog)
0276 pr_crit("%s in danger of initiating system reset "
0277 "in %ld.%01ld seconds\n",
0278 ident.identity,
0279 wd_init / 1000000, (wd_init / 100000) % 10);
0280 else
0281 cfg |= 1;
0282
0283 __raw_writeb(cfg, wd_cfg_reg);
0284
0285 return IRQ_HANDLED;
0286 }
0287
0288 static int __init sbwdog_init(void)
0289 {
0290 int ret;
0291
0292
0293
0294
0295 ret = register_reboot_notifier(&sbwdog_notifier);
0296 if (ret) {
0297 pr_err("%s: cannot register reboot notifier (err=%d)\n",
0298 ident.identity, ret);
0299 return ret;
0300 }
0301
0302
0303
0304
0305
0306 ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED,
0307 ident.identity, (void *)user_dog);
0308 if (ret) {
0309 pr_err("%s: failed to request irq 1 - %d\n",
0310 ident.identity, ret);
0311 goto out;
0312 }
0313
0314 ret = misc_register(&sbwdog_miscdev);
0315 if (ret == 0) {
0316 pr_info("%s: timeout is %ld.%ld secs\n",
0317 ident.identity,
0318 timeout / 1000000, (timeout / 100000) % 10);
0319 return 0;
0320 }
0321 free_irq(1, (void *)user_dog);
0322 out:
0323 unregister_reboot_notifier(&sbwdog_notifier);
0324
0325 return ret;
0326 }
0327
0328 static void __exit sbwdog_exit(void)
0329 {
0330 misc_deregister(&sbwdog_miscdev);
0331 free_irq(1, (void *)user_dog);
0332 unregister_reboot_notifier(&sbwdog_notifier);
0333 }
0334
0335 module_init(sbwdog_init);
0336 module_exit(sbwdog_exit);
0337
0338 MODULE_AUTHOR("Andrew Sharp <andy.sharp@lsi.com>");
0339 MODULE_DESCRIPTION("SiByte Watchdog");
0340
0341 module_param(timeout, ulong, 0);
0342 MODULE_PARM_DESC(timeout,
0343 "Watchdog timeout in microseconds (max/default 8388607 or 8.3ish secs)");
0344
0345 MODULE_LICENSE("GPL");
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363