Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* riowd.c - driver for hw watchdog inside Super I/O of RIO
0003  *
0004  * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
0005  */
0006 
0007 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/types.h>
0012 #include <linux/fs.h>
0013 #include <linux/errno.h>
0014 #include <linux/miscdevice.h>
0015 #include <linux/watchdog.h>
0016 #include <linux/of.h>
0017 #include <linux/of_device.h>
0018 #include <linux/io.h>
0019 #include <linux/uaccess.h>
0020 #include <linux/slab.h>
0021 
0022 
0023 /* RIO uses the NatSemi Super I/O power management logical device
0024  * as its' watchdog.
0025  *
0026  * When the watchdog triggers, it asserts a line to the BBC (Boot Bus
0027  * Controller) of the machine.  The BBC can only be configured to
0028  * trigger a power-on reset when the signal is asserted.  The BBC
0029  * can be configured to ignore the signal entirely as well.
0030  *
0031  * The only Super I/O device register we care about is at index
0032  * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255).
0033  * If set to zero, this disables the watchdog.  When set, the system
0034  * must periodically (before watchdog expires) clear (set to zero) and
0035  * re-set the watchdog else it will trigger.
0036  *
0037  * There are two other indexed watchdog registers inside this Super I/O
0038  * logical device, but they are unused.  The first, at index 0x06 is
0039  * the watchdog control and can be used to make the watchdog timer re-set
0040  * when the PS/2 mouse or serial lines show activity.  The second, at
0041  * index 0x07 is merely a sampling of the line from the watchdog to the
0042  * BBC.
0043  *
0044  * The watchdog device generates no interrupts.
0045  */
0046 
0047 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
0048 MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
0049 MODULE_LICENSE("GPL");
0050 
0051 #define DRIVER_NAME "riowd"
0052 #define PFX     DRIVER_NAME ": "
0053 
0054 struct riowd {
0055     void __iomem        *regs;
0056     spinlock_t      lock;
0057 };
0058 
0059 static struct riowd *riowd_device;
0060 
0061 #define WDTO_INDEX  0x05
0062 
0063 static int riowd_timeout = 1;       /* in minutes */
0064 module_param(riowd_timeout, int, 0);
0065 MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
0066 
0067 static void riowd_writereg(struct riowd *p, u8 val, int index)
0068 {
0069     unsigned long flags;
0070 
0071     spin_lock_irqsave(&p->lock, flags);
0072     writeb(index, p->regs + 0);
0073     writeb(val, p->regs + 1);
0074     spin_unlock_irqrestore(&p->lock, flags);
0075 }
0076 
0077 static int riowd_open(struct inode *inode, struct file *filp)
0078 {
0079     stream_open(inode, filp);
0080     return 0;
0081 }
0082 
0083 static int riowd_release(struct inode *inode, struct file *filp)
0084 {
0085     return 0;
0086 }
0087 
0088 static long riowd_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
0089 {
0090     static const struct watchdog_info info = {
0091         .options        = WDIOF_SETTIMEOUT,
0092         .firmware_version   = 1,
0093         .identity       = DRIVER_NAME,
0094     };
0095     void __user *argp = (void __user *)arg;
0096     struct riowd *p = riowd_device;
0097     unsigned int options;
0098     int new_margin;
0099 
0100     switch (cmd) {
0101     case WDIOC_GETSUPPORT:
0102         if (copy_to_user(argp, &info, sizeof(info)))
0103             return -EFAULT;
0104         break;
0105 
0106     case WDIOC_GETSTATUS:
0107     case WDIOC_GETBOOTSTATUS:
0108         if (put_user(0, (int __user *)argp))
0109             return -EFAULT;
0110         break;
0111 
0112     case WDIOC_KEEPALIVE:
0113         riowd_writereg(p, riowd_timeout, WDTO_INDEX);
0114         break;
0115 
0116     case WDIOC_SETOPTIONS:
0117         if (copy_from_user(&options, argp, sizeof(options)))
0118             return -EFAULT;
0119 
0120         if (options & WDIOS_DISABLECARD)
0121             riowd_writereg(p, 0, WDTO_INDEX);
0122         else if (options & WDIOS_ENABLECARD)
0123             riowd_writereg(p, riowd_timeout, WDTO_INDEX);
0124         else
0125             return -EINVAL;
0126 
0127         break;
0128 
0129     case WDIOC_SETTIMEOUT:
0130         if (get_user(new_margin, (int __user *)argp))
0131             return -EFAULT;
0132         if ((new_margin < 60) || (new_margin > (255 * 60)))
0133             return -EINVAL;
0134         riowd_timeout = (new_margin + 59) / 60;
0135         riowd_writereg(p, riowd_timeout, WDTO_INDEX);
0136         fallthrough;
0137 
0138     case WDIOC_GETTIMEOUT:
0139         return put_user(riowd_timeout * 60, (int __user *)argp);
0140 
0141     default:
0142         return -EINVAL;
0143     }
0144 
0145     return 0;
0146 }
0147 
0148 static ssize_t riowd_write(struct file *file, const char __user *buf,
0149                         size_t count, loff_t *ppos)
0150 {
0151     struct riowd *p = riowd_device;
0152 
0153     if (count) {
0154         riowd_writereg(p, riowd_timeout, WDTO_INDEX);
0155         return 1;
0156     }
0157 
0158     return 0;
0159 }
0160 
0161 static const struct file_operations riowd_fops = {
0162     .owner =        THIS_MODULE,
0163     .llseek =       no_llseek,
0164     .unlocked_ioctl =   riowd_ioctl,
0165     .compat_ioctl   =   compat_ptr_ioctl,
0166     .open =         riowd_open,
0167     .write =        riowd_write,
0168     .release =      riowd_release,
0169 };
0170 
0171 static struct miscdevice riowd_miscdev = {
0172     .minor  = WATCHDOG_MINOR,
0173     .name   = "watchdog",
0174     .fops   = &riowd_fops
0175 };
0176 
0177 static int riowd_probe(struct platform_device *op)
0178 {
0179     struct riowd *p;
0180     int err = -EINVAL;
0181 
0182     if (riowd_device)
0183         goto out;
0184 
0185     err = -ENOMEM;
0186     p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
0187     if (!p)
0188         goto out;
0189 
0190     spin_lock_init(&p->lock);
0191 
0192     p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
0193     if (!p->regs) {
0194         pr_err("Cannot map registers\n");
0195         goto out;
0196     }
0197     /* Make miscdev useable right away */
0198     riowd_device = p;
0199 
0200     err = misc_register(&riowd_miscdev);
0201     if (err) {
0202         pr_err("Cannot register watchdog misc device\n");
0203         goto out_iounmap;
0204     }
0205 
0206     pr_info("Hardware watchdog [%i minutes], regs at %p\n",
0207         riowd_timeout, p->regs);
0208 
0209     platform_set_drvdata(op, p);
0210     return 0;
0211 
0212 out_iounmap:
0213     riowd_device = NULL;
0214     of_iounmap(&op->resource[0], p->regs, 2);
0215 
0216 out:
0217     return err;
0218 }
0219 
0220 static int riowd_remove(struct platform_device *op)
0221 {
0222     struct riowd *p = platform_get_drvdata(op);
0223 
0224     misc_deregister(&riowd_miscdev);
0225     of_iounmap(&op->resource[0], p->regs, 2);
0226 
0227     return 0;
0228 }
0229 
0230 static const struct of_device_id riowd_match[] = {
0231     {
0232         .name = "pmc",
0233     },
0234     {},
0235 };
0236 MODULE_DEVICE_TABLE(of, riowd_match);
0237 
0238 static struct platform_driver riowd_driver = {
0239     .driver = {
0240         .name = DRIVER_NAME,
0241         .of_match_table = riowd_match,
0242     },
0243     .probe      = riowd_probe,
0244     .remove     = riowd_remove,
0245 };
0246 
0247 module_platform_driver(riowd_driver);