Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * GE watchdog userspace interface
0004  *
0005  * Author:  Martyn Welch <martyn.welch@ge.com>
0006  *
0007  * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
0008  *
0009  * Based on: mv64x60_wdt.c (MV64X60 watchdog userspace interface)
0010  *   Author: James Chapman <jchapman@katalix.com>
0011  */
0012 
0013 /* TODO:
0014  * This driver does not provide support for the hardwares capability of sending
0015  * an interrupt at a programmable threshold.
0016  *
0017  * This driver currently can only support 1 watchdog - there are 2 in the
0018  * hardware that this driver supports. Thus one could be configured as a
0019  * process-based watchdog (via /dev/watchdog), the second (using the interrupt
0020  * capabilities) a kernel-based watchdog.
0021  */
0022 
0023 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0024 
0025 #include <linux/kernel.h>
0026 #include <linux/compiler.h>
0027 #include <linux/init.h>
0028 #include <linux/module.h>
0029 #include <linux/miscdevice.h>
0030 #include <linux/watchdog.h>
0031 #include <linux/fs.h>
0032 #include <linux/of.h>
0033 #include <linux/of_address.h>
0034 #include <linux/of_platform.h>
0035 #include <linux/io.h>
0036 #include <linux/uaccess.h>
0037 
0038 #include <sysdev/fsl_soc.h>
0039 
0040 /*
0041  * The watchdog configuration register contains a pair of 2-bit fields,
0042  *   1.  a reload field, bits 27-26, which triggers a reload of
0043  *       the countdown register, and
0044  *   2.  an enable field, bits 25-24, which toggles between
0045  *       enabling and disabling the watchdog timer.
0046  * Bit 31 is a read-only field which indicates whether the
0047  * watchdog timer is currently enabled.
0048  *
0049  * The low 24 bits contain the timer reload value.
0050  */
0051 #define GEF_WDC_ENABLE_SHIFT    24
0052 #define GEF_WDC_SERVICE_SHIFT   26
0053 #define GEF_WDC_ENABLED_SHIFT   31
0054 
0055 #define GEF_WDC_ENABLED_TRUE    1
0056 #define GEF_WDC_ENABLED_FALSE   0
0057 
0058 /* Flags bits */
0059 #define GEF_WDOG_FLAG_OPENED    0
0060 
0061 static unsigned long wdt_flags;
0062 static int wdt_status;
0063 static void __iomem *gef_wdt_regs;
0064 static int gef_wdt_timeout;
0065 static int gef_wdt_count;
0066 static unsigned int bus_clk;
0067 static char expect_close;
0068 static DEFINE_SPINLOCK(gef_wdt_spinlock);
0069 
0070 static bool nowayout = WATCHDOG_NOWAYOUT;
0071 module_param(nowayout, bool, 0);
0072 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
0073     __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0074 
0075 
0076 static int gef_wdt_toggle_wdc(int enabled_predicate, int field_shift)
0077 {
0078     u32 data;
0079     u32 enabled;
0080     int ret = 0;
0081 
0082     spin_lock(&gef_wdt_spinlock);
0083     data = ioread32be(gef_wdt_regs);
0084     enabled = (data >> GEF_WDC_ENABLED_SHIFT) & 1;
0085 
0086     /* only toggle the requested field if enabled state matches predicate */
0087     if ((enabled ^ enabled_predicate) == 0) {
0088         /* We write a 1, then a 2 -- to the appropriate field */
0089         data = (1 << field_shift) | gef_wdt_count;
0090         iowrite32be(data, gef_wdt_regs);
0091 
0092         data = (2 << field_shift) | gef_wdt_count;
0093         iowrite32be(data, gef_wdt_regs);
0094         ret = 1;
0095     }
0096     spin_unlock(&gef_wdt_spinlock);
0097 
0098     return ret;
0099 }
0100 
0101 static void gef_wdt_service(void)
0102 {
0103     gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE,
0104         GEF_WDC_SERVICE_SHIFT);
0105 }
0106 
0107 static void gef_wdt_handler_enable(void)
0108 {
0109     if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_FALSE,
0110                    GEF_WDC_ENABLE_SHIFT)) {
0111         gef_wdt_service();
0112         pr_notice("watchdog activated\n");
0113     }
0114 }
0115 
0116 static void gef_wdt_handler_disable(void)
0117 {
0118     if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE,
0119                    GEF_WDC_ENABLE_SHIFT))
0120         pr_notice("watchdog deactivated\n");
0121 }
0122 
0123 static void gef_wdt_set_timeout(unsigned int timeout)
0124 {
0125     /* maximum bus cycle count is 0xFFFFFFFF */
0126     if (timeout > 0xFFFFFFFF / bus_clk)
0127         timeout = 0xFFFFFFFF / bus_clk;
0128 
0129     /* Register only holds upper 24 bits, bit shifted into lower 24 */
0130     gef_wdt_count = (timeout * bus_clk) >> 8;
0131     gef_wdt_timeout = timeout;
0132 }
0133 
0134 
0135 static ssize_t gef_wdt_write(struct file *file, const char __user *data,
0136                  size_t len, loff_t *ppos)
0137 {
0138     if (len) {
0139         if (!nowayout) {
0140             size_t i;
0141 
0142             expect_close = 0;
0143 
0144             for (i = 0; i != len; i++) {
0145                 char c;
0146                 if (get_user(c, data + i))
0147                     return -EFAULT;
0148                 if (c == 'V')
0149                     expect_close = 42;
0150             }
0151         }
0152         gef_wdt_service();
0153     }
0154 
0155     return len;
0156 }
0157 
0158 static long gef_wdt_ioctl(struct file *file, unsigned int cmd,
0159                             unsigned long arg)
0160 {
0161     int timeout;
0162     int options;
0163     void __user *argp = (void __user *)arg;
0164     static const struct watchdog_info info = {
0165         .options =  WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
0166                 WDIOF_KEEPALIVEPING,
0167         .firmware_version = 0,
0168         .identity = "GE watchdog",
0169     };
0170 
0171     switch (cmd) {
0172     case WDIOC_GETSUPPORT:
0173         if (copy_to_user(argp, &info, sizeof(info)))
0174             return -EFAULT;
0175         break;
0176 
0177     case WDIOC_GETSTATUS:
0178     case WDIOC_GETBOOTSTATUS:
0179         if (put_user(wdt_status, (int __user *)argp))
0180             return -EFAULT;
0181         wdt_status &= ~WDIOF_KEEPALIVEPING;
0182         break;
0183 
0184     case WDIOC_SETOPTIONS:
0185         if (get_user(options, (int __user *)argp))
0186             return -EFAULT;
0187 
0188         if (options & WDIOS_DISABLECARD)
0189             gef_wdt_handler_disable();
0190 
0191         if (options & WDIOS_ENABLECARD)
0192             gef_wdt_handler_enable();
0193         break;
0194 
0195     case WDIOC_KEEPALIVE:
0196         gef_wdt_service();
0197         wdt_status |= WDIOF_KEEPALIVEPING;
0198         break;
0199 
0200     case WDIOC_SETTIMEOUT:
0201         if (get_user(timeout, (int __user *)argp))
0202             return -EFAULT;
0203         gef_wdt_set_timeout(timeout);
0204         fallthrough;
0205 
0206     case WDIOC_GETTIMEOUT:
0207         if (put_user(gef_wdt_timeout, (int __user *)argp))
0208             return -EFAULT;
0209         break;
0210 
0211     default:
0212         return -ENOTTY;
0213     }
0214 
0215     return 0;
0216 }
0217 
0218 static int gef_wdt_open(struct inode *inode, struct file *file)
0219 {
0220     if (test_and_set_bit(GEF_WDOG_FLAG_OPENED, &wdt_flags))
0221         return -EBUSY;
0222 
0223     if (nowayout)
0224         __module_get(THIS_MODULE);
0225 
0226     gef_wdt_handler_enable();
0227 
0228     return stream_open(inode, file);
0229 }
0230 
0231 static int gef_wdt_release(struct inode *inode, struct file *file)
0232 {
0233     if (expect_close == 42)
0234         gef_wdt_handler_disable();
0235     else {
0236         pr_crit("unexpected close, not stopping timer!\n");
0237         gef_wdt_service();
0238     }
0239     expect_close = 0;
0240 
0241     clear_bit(GEF_WDOG_FLAG_OPENED, &wdt_flags);
0242 
0243     return 0;
0244 }
0245 
0246 static const struct file_operations gef_wdt_fops = {
0247     .owner = THIS_MODULE,
0248     .llseek = no_llseek,
0249     .write = gef_wdt_write,
0250     .unlocked_ioctl = gef_wdt_ioctl,
0251     .compat_ioctl   = compat_ptr_ioctl,
0252     .open = gef_wdt_open,
0253     .release = gef_wdt_release,
0254 };
0255 
0256 static struct miscdevice gef_wdt_miscdev = {
0257     .minor = WATCHDOG_MINOR,
0258     .name = "watchdog",
0259     .fops = &gef_wdt_fops,
0260 };
0261 
0262 
0263 static int gef_wdt_probe(struct platform_device *dev)
0264 {
0265     int timeout = 10;
0266     u32 freq;
0267 
0268     bus_clk = 133; /* in MHz */
0269 
0270     freq = fsl_get_sys_freq();
0271     if (freq != -1)
0272         bus_clk = freq;
0273 
0274     /* Map devices registers into memory */
0275     gef_wdt_regs = of_iomap(dev->dev.of_node, 0);
0276     if (gef_wdt_regs == NULL)
0277         return -ENOMEM;
0278 
0279     gef_wdt_set_timeout(timeout);
0280 
0281     gef_wdt_handler_disable();  /* in case timer was already running */
0282 
0283     return misc_register(&gef_wdt_miscdev);
0284 }
0285 
0286 static int gef_wdt_remove(struct platform_device *dev)
0287 {
0288     misc_deregister(&gef_wdt_miscdev);
0289 
0290     gef_wdt_handler_disable();
0291 
0292     iounmap(gef_wdt_regs);
0293 
0294     return 0;
0295 }
0296 
0297 static const struct of_device_id gef_wdt_ids[] = {
0298     {
0299         .compatible = "gef,fpga-wdt",
0300     },
0301     {},
0302 };
0303 MODULE_DEVICE_TABLE(of, gef_wdt_ids);
0304 
0305 static struct platform_driver gef_wdt_driver = {
0306     .driver = {
0307         .name = "gef_wdt",
0308         .of_match_table = gef_wdt_ids,
0309     },
0310     .probe      = gef_wdt_probe,
0311     .remove     = gef_wdt_remove,
0312 };
0313 
0314 static int __init gef_wdt_init(void)
0315 {
0316     pr_info("GE watchdog driver\n");
0317     return platform_driver_register(&gef_wdt_driver);
0318 }
0319 
0320 static void __exit gef_wdt_exit(void)
0321 {
0322     platform_driver_unregister(&gef_wdt_driver);
0323 }
0324 
0325 module_init(gef_wdt_init);
0326 module_exit(gef_wdt_exit);
0327 
0328 MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>");
0329 MODULE_DESCRIPTION("GE watchdog driver");
0330 MODULE_LICENSE("GPL");
0331 MODULE_ALIAS("platform:gef_wdt");