brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 78681d9 Raw
225 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *	Intel 21285 watchdog driver4 *	Copyright (c) Phil Blundell <pb@nexus.co.uk>, 19985 *6 *	based on7 *8 *	SoftDog	0.05:	A Software Watchdog Device9 *10 *	(c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,11 *						All Rights Reserved.12 */13 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt15 16#include <linux/module.h>17#include <linux/moduleparam.h>18#include <linux/types.h>19#include <linux/kernel.h>20#include <linux/fs.h>21#include <linux/mm.h>22#include <linux/miscdevice.h>23#include <linux/watchdog.h>24#include <linux/reboot.h>25#include <linux/init.h>26#include <linux/interrupt.h>27#include <linux/uaccess.h>28#include <linux/irq.h>29#include <mach/hardware.h>30 31#include <asm/mach-types.h>32#include <asm/system_info.h>33#include <asm/hardware/dec21285.h>34 35/*36 * Define this to stop the watchdog actually rebooting the machine.37 */38#undef ONLY_TESTING39 40static unsigned int soft_margin = 60;		/* in seconds */41static unsigned int reload;42static unsigned long timer_alive;43 44#ifdef ONLY_TESTING45/*46 *	If the timer expires..47 */48static void watchdog_fire(int irq, void *dev_id)49{50	pr_crit("Would Reboot\n");51	*CSR_TIMER4_CNTL = 0;52	*CSR_TIMER4_CLR = 0;53}54#endif55 56/*57 *	Refresh the timer.58 */59static void watchdog_ping(void)60{61	*CSR_TIMER4_LOAD = reload;62}63 64/*65 *	Allow only one person to hold it open66 */67static int watchdog_open(struct inode *inode, struct file *file)68{69	int ret;70 71	if (*CSR_SA110_CNTL & (1 << 13))72		return -EBUSY;73 74	if (test_and_set_bit(1, &timer_alive))75		return -EBUSY;76 77	reload = soft_margin * (mem_fclk_21285 / 256);78 79	*CSR_TIMER4_CLR = 0;80	watchdog_ping();81	*CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD82		| TIMER_CNTL_DIV256;83 84#ifdef ONLY_TESTING85	ret = request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL);86	if (ret) {87		*CSR_TIMER4_CNTL = 0;88		clear_bit(1, &timer_alive);89	}90#else91	/*92	 * Setting this bit is irreversible; once enabled, there is93	 * no way to disable the watchdog.94	 */95	*CSR_SA110_CNTL |= 1 << 13;96 97	ret = 0;98#endif99	stream_open(inode, file);100	return ret;101}102 103/*104 *	Shut off the timer.105 *	Note: if we really have enabled the watchdog, there106 *	is no way to turn off.107 */108static int watchdog_release(struct inode *inode, struct file *file)109{110#ifdef ONLY_TESTING111	free_irq(IRQ_TIMER4, NULL);112	clear_bit(1, &timer_alive);113#endif114	return 0;115}116 117static ssize_t watchdog_write(struct file *file, const char __user *data,118			      size_t len, loff_t *ppos)119{120	/*121	 *	Refresh the timer.122	 */123	if (len)124		watchdog_ping();125 126	return len;127}128 129static const struct watchdog_info ident = {130	.options	= WDIOF_SETTIMEOUT,131	.identity	= "Footbridge Watchdog",132};133 134static long watchdog_ioctl(struct file *file, unsigned int cmd,135			   unsigned long arg)136{137	int __user *int_arg = (int __user *)arg;138	int new_margin, ret = -ENOTTY;139 140	switch (cmd) {141	case WDIOC_GETSUPPORT:142		ret = 0;143		if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))144			ret = -EFAULT;145		break;146 147	case WDIOC_GETSTATUS:148	case WDIOC_GETBOOTSTATUS:149		ret = put_user(0, int_arg);150		break;151 152	case WDIOC_KEEPALIVE:153		watchdog_ping();154		ret = 0;155		break;156 157	case WDIOC_SETTIMEOUT:158		ret = get_user(new_margin, int_arg);159		if (ret)160			break;161 162		/* Arbitrary, can't find the card's limits */163		if (new_margin < 0 || new_margin > 60) {164			ret = -EINVAL;165			break;166		}167 168		soft_margin = new_margin;169		reload = soft_margin * (mem_fclk_21285 / 256);170		watchdog_ping();171		fallthrough;172	case WDIOC_GETTIMEOUT:173		ret = put_user(soft_margin, int_arg);174		break;175	}176	return ret;177}178 179static const struct file_operations watchdog_fops = {180	.owner		= THIS_MODULE,181	.write		= watchdog_write,182	.unlocked_ioctl	= watchdog_ioctl,183	.compat_ioctl	= compat_ptr_ioctl,184	.open		= watchdog_open,185	.release	= watchdog_release,186};187 188static struct miscdevice watchdog_miscdev = {189	.minor		= WATCHDOG_MINOR,190	.name		= "watchdog",191	.fops		= &watchdog_fops,192};193 194static int __init footbridge_watchdog_init(void)195{196	int retval;197 198	if (machine_is_netwinder())199		return -ENODEV;200 201	retval = misc_register(&watchdog_miscdev);202	if (retval < 0)203		return retval;204 205	pr_info("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",206		soft_margin);207 208	return 0;209}210 211static void __exit footbridge_watchdog_exit(void)212{213	misc_deregister(&watchdog_miscdev);214}215 216MODULE_AUTHOR("Phil Blundell <pb@nexus.co.uk>");217MODULE_DESCRIPTION("Footbridge watchdog driver");218MODULE_LICENSE("GPL");219 220module_param(soft_margin, int, 0);221MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");222 223module_init(footbridge_watchdog_init);224module_exit(footbridge_watchdog_exit);225