0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0019
0020 #include <linux/kernel.h>
0021 #include <linux/module.h>
0022 #include <linux/fs.h>
0023 #include <linux/errno.h>
0024 #include <linux/major.h>
0025 #include <linux/miscdevice.h>
0026 #include <linux/interrupt.h>
0027 #include <linux/ioport.h>
0028 #include <linux/timer.h>
0029 #include <linux/compat.h>
0030 #include <linux/slab.h>
0031 #include <linux/mutex.h>
0032 #include <linux/io.h>
0033 #include <linux/of.h>
0034 #include <linux/of_device.h>
0035 #include <linux/uaccess.h>
0036
0037 #include <asm/irq.h>
0038 #include <asm/watchdog.h>
0039
0040 #define DRIVER_NAME "cpwd"
0041
0042 #define WD_OBPNAME "watchdog"
0043 #define WD_BADMODEL "SUNW,501-5336"
0044 #define WD_BTIMEOUT (jiffies + (HZ * 1000))
0045 #define WD_BLIMIT 0xFFFF
0046
0047 #define WD0_MINOR 212
0048 #define WD1_MINOR 213
0049 #define WD2_MINOR 214
0050
0051
0052 #define WD0_ID 0
0053 #define WD1_ID 1
0054 #define WD2_ID 2
0055 #define WD_NUMDEVS 3
0056
0057 #define WD_INTR_OFF 0
0058 #define WD_INTR_ON 1
0059
0060 #define WD_STAT_INIT 0x01
0061 #define WD_STAT_BSTOP 0x02
0062 #define WD_STAT_SVCD 0x04
0063
0064
0065
0066 #define WD0_INTR_MASK 0x01
0067 #define WD1_INTR_MASK 0x02
0068 #define WD2_INTR_MASK 0x04
0069
0070 #define WD_S_RUNNING 0x01
0071 #define WD_S_EXPIRED 0x02
0072
0073 struct cpwd {
0074 void __iomem *regs;
0075 spinlock_t lock;
0076
0077 unsigned int irq;
0078
0079 unsigned long timeout;
0080 bool enabled;
0081 bool reboot;
0082 bool broken;
0083 bool initialized;
0084
0085 struct {
0086 struct miscdevice misc;
0087 void __iomem *regs;
0088 u8 intr_mask;
0089 u8 runstatus;
0090 u16 timeout;
0091 } devs[WD_NUMDEVS];
0092 };
0093
0094 static DEFINE_MUTEX(cpwd_mutex);
0095 static struct cpwd *cpwd_device;
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 #define WD_TIMER_REGSZ 16
0147 #define WD0_OFF 0
0148 #define WD1_OFF (WD_TIMER_REGSZ * 1)
0149 #define WD2_OFF (WD_TIMER_REGSZ * 2)
0150 #define PLD_OFF (WD_TIMER_REGSZ * 3)
0151
0152 #define WD_DCNTR 0x00
0153 #define WD_LIMIT 0x04
0154 #define WD_STATUS 0x08
0155
0156 #define PLD_IMASK (PLD_OFF + 0x00)
0157 #define PLD_STATUS (PLD_OFF + 0x04)
0158
0159 static struct timer_list cpwd_timer;
0160
0161 static int wd0_timeout;
0162 static int wd1_timeout;
0163 static int wd2_timeout;
0164
0165 module_param(wd0_timeout, int, 0);
0166 MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
0167 module_param(wd1_timeout, int, 0);
0168 MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
0169 module_param(wd2_timeout, int, 0);
0170 MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
0171
0172 MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
0173 MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500");
0174 MODULE_LICENSE("GPL");
0175
0176 static void cpwd_writew(u16 val, void __iomem *addr)
0177 {
0178 writew(cpu_to_le16(val), addr);
0179 }
0180 static u16 cpwd_readw(void __iomem *addr)
0181 {
0182 u16 val = readw(addr);
0183
0184 return le16_to_cpu(val);
0185 }
0186
0187 static void cpwd_writeb(u8 val, void __iomem *addr)
0188 {
0189 writeb(val, addr);
0190 }
0191
0192 static u8 cpwd_readb(void __iomem *addr)
0193 {
0194 return readb(addr);
0195 }
0196
0197
0198
0199
0200
0201
0202
0203
0204 static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
0205 {
0206 unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK);
0207 unsigned char setregs =
0208 (index == -1) ?
0209 (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) :
0210 (p->devs[index].intr_mask);
0211
0212 if (enable == WD_INTR_ON)
0213 curregs &= ~setregs;
0214 else
0215 curregs |= setregs;
0216
0217 cpwd_writeb(curregs, p->regs + PLD_IMASK);
0218 }
0219
0220
0221
0222
0223 static void cpwd_resetbrokentimer(struct cpwd *p, int index)
0224 {
0225 cpwd_toggleintr(p, index, WD_INTR_ON);
0226 cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT);
0227 }
0228
0229
0230
0231
0232
0233
0234 static void cpwd_brokentimer(struct timer_list *unused)
0235 {
0236 struct cpwd *p = cpwd_device;
0237 int id, tripped = 0;
0238
0239
0240
0241
0242 if (timer_pending(&cpwd_timer))
0243 del_timer(&cpwd_timer);
0244
0245 for (id = 0; id < WD_NUMDEVS; id++) {
0246 if (p->devs[id].runstatus & WD_STAT_BSTOP) {
0247 ++tripped;
0248 cpwd_resetbrokentimer(p, id);
0249 }
0250 }
0251
0252 if (tripped) {
0253
0254 cpwd_timer.expires = WD_BTIMEOUT;
0255 add_timer(&cpwd_timer);
0256 }
0257 }
0258
0259
0260
0261
0262 static void cpwd_pingtimer(struct cpwd *p, int index)
0263 {
0264 if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING)
0265 cpwd_readw(p->devs[index].regs + WD_DCNTR);
0266 }
0267
0268
0269
0270
0271
0272 static void cpwd_stoptimer(struct cpwd *p, int index)
0273 {
0274 if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) {
0275 cpwd_toggleintr(p, index, WD_INTR_OFF);
0276
0277 if (p->broken) {
0278 p->devs[index].runstatus |= WD_STAT_BSTOP;
0279 cpwd_brokentimer(NULL);
0280 }
0281 }
0282 }
0283
0284
0285
0286
0287
0288
0289
0290
0291 static void cpwd_starttimer(struct cpwd *p, int index)
0292 {
0293 if (p->broken)
0294 p->devs[index].runstatus &= ~WD_STAT_BSTOP;
0295
0296 p->devs[index].runstatus &= ~WD_STAT_SVCD;
0297
0298 cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT);
0299 cpwd_toggleintr(p, index, WD_INTR_ON);
0300 }
0301
0302 static int cpwd_getstatus(struct cpwd *p, int index)
0303 {
0304 unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS);
0305 unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK);
0306 unsigned char ret = WD_STOPPED;
0307
0308
0309 if (!stat)
0310 return ret;
0311
0312
0313 else if (WD_S_EXPIRED & stat) {
0314 ret = WD_EXPIRED;
0315 } else if (WD_S_RUNNING & stat) {
0316 if (intr & p->devs[index].intr_mask) {
0317 ret = WD_FREERUN;
0318 } else {
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330 if (p->broken &&
0331 (p->devs[index].runstatus & WD_STAT_BSTOP)) {
0332 if (p->devs[index].runstatus & WD_STAT_SVCD) {
0333 ret = WD_EXPIRED;
0334 } else {
0335
0336
0337 ret = WD_FREERUN;
0338 }
0339 } else {
0340 ret = WD_RUNNING;
0341 }
0342 }
0343 }
0344
0345
0346 if (p->devs[index].runstatus & WD_STAT_SVCD)
0347 ret |= WD_SERVICED;
0348
0349 return ret;
0350 }
0351
0352 static irqreturn_t cpwd_interrupt(int irq, void *dev_id)
0353 {
0354 struct cpwd *p = dev_id;
0355
0356
0357
0358
0359 spin_lock_irq(&p->lock);
0360
0361 cpwd_stoptimer(p, WD0_ID);
0362 p->devs[WD0_ID].runstatus |= WD_STAT_SVCD;
0363
0364 spin_unlock_irq(&p->lock);
0365
0366 return IRQ_HANDLED;
0367 }
0368
0369 static int cpwd_open(struct inode *inode, struct file *f)
0370 {
0371 struct cpwd *p = cpwd_device;
0372
0373 mutex_lock(&cpwd_mutex);
0374 switch (iminor(inode)) {
0375 case WD0_MINOR:
0376 case WD1_MINOR:
0377 case WD2_MINOR:
0378 break;
0379
0380 default:
0381 mutex_unlock(&cpwd_mutex);
0382 return -ENODEV;
0383 }
0384
0385
0386 if (!p->initialized) {
0387 if (request_irq(p->irq, &cpwd_interrupt,
0388 IRQF_SHARED, DRIVER_NAME, p)) {
0389 pr_err("Cannot register IRQ %d\n", p->irq);
0390 mutex_unlock(&cpwd_mutex);
0391 return -EBUSY;
0392 }
0393 p->initialized = true;
0394 }
0395
0396 mutex_unlock(&cpwd_mutex);
0397
0398 return stream_open(inode, f);
0399 }
0400
0401 static int cpwd_release(struct inode *inode, struct file *file)
0402 {
0403 return 0;
0404 }
0405
0406 static long cpwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0407 {
0408 static const struct watchdog_info info = {
0409 .options = WDIOF_SETTIMEOUT,
0410 .firmware_version = 1,
0411 .identity = DRIVER_NAME,
0412 };
0413 void __user *argp = (void __user *)arg;
0414 struct inode *inode = file_inode(file);
0415 int index = iminor(inode) - WD0_MINOR;
0416 struct cpwd *p = cpwd_device;
0417 int setopt = 0;
0418
0419 switch (cmd) {
0420
0421 case WDIOC_GETSUPPORT:
0422 if (copy_to_user(argp, &info, sizeof(struct watchdog_info)))
0423 return -EFAULT;
0424 break;
0425
0426 case WDIOC_GETSTATUS:
0427 case WDIOC_GETBOOTSTATUS:
0428 if (put_user(0, (int __user *)argp))
0429 return -EFAULT;
0430 break;
0431
0432 case WDIOC_KEEPALIVE:
0433 cpwd_pingtimer(p, index);
0434 break;
0435
0436 case WDIOC_SETOPTIONS:
0437 if (copy_from_user(&setopt, argp, sizeof(unsigned int)))
0438 return -EFAULT;
0439
0440 if (setopt & WDIOS_DISABLECARD) {
0441 if (p->enabled)
0442 return -EINVAL;
0443 cpwd_stoptimer(p, index);
0444 } else if (setopt & WDIOS_ENABLECARD) {
0445 cpwd_starttimer(p, index);
0446 } else {
0447 return -EINVAL;
0448 }
0449 break;
0450
0451
0452 case WIOCGSTAT:
0453 setopt = cpwd_getstatus(p, index);
0454 if (copy_to_user(argp, &setopt, sizeof(unsigned int)))
0455 return -EFAULT;
0456 break;
0457
0458 case WIOCSTART:
0459 cpwd_starttimer(p, index);
0460 break;
0461
0462 case WIOCSTOP:
0463 if (p->enabled)
0464 return -EINVAL;
0465
0466 cpwd_stoptimer(p, index);
0467 break;
0468
0469 default:
0470 return -EINVAL;
0471 }
0472
0473 return 0;
0474 }
0475
0476 static long cpwd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0477 {
0478 return cpwd_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
0479 }
0480
0481 static ssize_t cpwd_write(struct file *file, const char __user *buf,
0482 size_t count, loff_t *ppos)
0483 {
0484 struct inode *inode = file_inode(file);
0485 struct cpwd *p = cpwd_device;
0486 int index = iminor(inode);
0487
0488 if (count) {
0489 cpwd_pingtimer(p, index);
0490 return 1;
0491 }
0492
0493 return 0;
0494 }
0495
0496 static ssize_t cpwd_read(struct file *file, char __user *buffer,
0497 size_t count, loff_t *ppos)
0498 {
0499 return -EINVAL;
0500 }
0501
0502 static const struct file_operations cpwd_fops = {
0503 .owner = THIS_MODULE,
0504 .unlocked_ioctl = cpwd_ioctl,
0505 .compat_ioctl = cpwd_compat_ioctl,
0506 .open = cpwd_open,
0507 .write = cpwd_write,
0508 .read = cpwd_read,
0509 .release = cpwd_release,
0510 .llseek = no_llseek,
0511 };
0512
0513 static int cpwd_probe(struct platform_device *op)
0514 {
0515 struct device_node *options;
0516 const char *str_prop;
0517 const void *prop_val;
0518 int i, err = -EINVAL;
0519 struct cpwd *p;
0520
0521 if (cpwd_device)
0522 return -EINVAL;
0523
0524 p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
0525 if (!p)
0526 return -ENOMEM;
0527
0528 p->irq = op->archdata.irqs[0];
0529
0530 spin_lock_init(&p->lock);
0531
0532 p->regs = of_ioremap(&op->resource[0], 0,
0533 4 * WD_TIMER_REGSZ, DRIVER_NAME);
0534 if (!p->regs) {
0535 pr_err("Unable to map registers\n");
0536 return -ENOMEM;
0537 }
0538
0539 options = of_find_node_by_path("/options");
0540 if (!options) {
0541 err = -ENODEV;
0542 pr_err("Unable to find /options node\n");
0543 goto out_iounmap;
0544 }
0545
0546 prop_val = of_get_property(options, "watchdog-enable?", NULL);
0547 p->enabled = (prop_val ? true : false);
0548
0549 prop_val = of_get_property(options, "watchdog-reboot?", NULL);
0550 p->reboot = (prop_val ? true : false);
0551
0552 str_prop = of_get_property(options, "watchdog-timeout", NULL);
0553 if (str_prop)
0554 p->timeout = simple_strtoul(str_prop, NULL, 10);
0555
0556 of_node_put(options);
0557
0558
0559
0560
0561
0562 str_prop = of_get_property(op->dev.of_node, "model", NULL);
0563 p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL));
0564
0565 if (!p->enabled)
0566 cpwd_toggleintr(p, -1, WD_INTR_OFF);
0567
0568 for (i = 0; i < WD_NUMDEVS; i++) {
0569 static const char *cpwd_names[] = { "RIC", "XIR", "POR" };
0570 static int *parms[] = { &wd0_timeout,
0571 &wd1_timeout,
0572 &wd2_timeout };
0573 struct miscdevice *mp = &p->devs[i].misc;
0574
0575 mp->minor = WD0_MINOR + i;
0576 mp->name = cpwd_names[i];
0577 mp->fops = &cpwd_fops;
0578
0579 p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ);
0580 p->devs[i].intr_mask = (WD0_INTR_MASK << i);
0581 p->devs[i].runstatus &= ~WD_STAT_BSTOP;
0582 p->devs[i].runstatus |= WD_STAT_INIT;
0583 p->devs[i].timeout = p->timeout;
0584 if (*parms[i])
0585 p->devs[i].timeout = *parms[i];
0586
0587 err = misc_register(&p->devs[i].misc);
0588 if (err) {
0589 pr_err("Could not register misc device for dev %d\n",
0590 i);
0591 goto out_unregister;
0592 }
0593 }
0594
0595 if (p->broken) {
0596 timer_setup(&cpwd_timer, cpwd_brokentimer, 0);
0597 cpwd_timer.expires = WD_BTIMEOUT;
0598
0599 pr_info("PLD defect workaround enabled for model %s\n",
0600 WD_BADMODEL);
0601 }
0602
0603 platform_set_drvdata(op, p);
0604 cpwd_device = p;
0605 return 0;
0606
0607 out_unregister:
0608 for (i--; i >= 0; i--)
0609 misc_deregister(&p->devs[i].misc);
0610
0611 out_iounmap:
0612 of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
0613
0614 return err;
0615 }
0616
0617 static int cpwd_remove(struct platform_device *op)
0618 {
0619 struct cpwd *p = platform_get_drvdata(op);
0620 int i;
0621
0622 for (i = 0; i < WD_NUMDEVS; i++) {
0623 misc_deregister(&p->devs[i].misc);
0624
0625 if (!p->enabled) {
0626 cpwd_stoptimer(p, i);
0627 if (p->devs[i].runstatus & WD_STAT_BSTOP)
0628 cpwd_resetbrokentimer(p, i);
0629 }
0630 }
0631
0632 if (p->broken)
0633 del_timer_sync(&cpwd_timer);
0634
0635 if (p->initialized)
0636 free_irq(p->irq, p);
0637
0638 of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
0639
0640 cpwd_device = NULL;
0641
0642 return 0;
0643 }
0644
0645 static const struct of_device_id cpwd_match[] = {
0646 {
0647 .name = "watchdog",
0648 },
0649 {},
0650 };
0651 MODULE_DEVICE_TABLE(of, cpwd_match);
0652
0653 static struct platform_driver cpwd_driver = {
0654 .driver = {
0655 .name = DRIVER_NAME,
0656 .of_match_table = cpwd_match,
0657 },
0658 .probe = cpwd_probe,
0659 .remove = cpwd_remove,
0660 };
0661
0662 module_platform_driver(cpwd_driver);