Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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