0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
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
0042
0043
0044
0045
0046
0047
0048
0049
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
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
0087 if ((enabled ^ enabled_predicate) == 0) {
0088
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
0126 if (timeout > 0xFFFFFFFF / bus_clk)
0127 timeout = 0xFFFFFFFF / bus_clk;
0128
0129
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;
0269
0270 freq = fsl_get_sys_freq();
0271 if (freq != -1)
0272 bus_clk = freq;
0273
0274
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();
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");