1/* $Id: riowatchdog.c,v 1.1.1.1 2007/08/03 18:52:55 Exp $ 2 * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO 3 * 4 * Copyright (C) 2001 David S. Miller (davem@redhat.com) 5 */ 6 7#include <linux/kernel.h> 8#include <linux/module.h> 9#include <linux/types.h> 10#include <linux/fs.h> 11#include <linux/errno.h> 12#include <linux/init.h> 13#include <linux/miscdevice.h> 14 15#include <asm/io.h> 16#include <asm/ebus.h> 17#include <asm/bbc.h> 18#include <asm/oplib.h> 19#include <asm/uaccess.h> 20 21#include <asm/watchdog.h> 22 23/* RIO uses the NatSemi Super I/O power management logical device 24 * as its' watchdog. 25 * 26 * When the watchdog triggers, it asserts a line to the BBC (Boot Bus 27 * Controller) of the machine. The BBC can only be configured to 28 * trigger a power-on reset when the signal is asserted. The BBC 29 * can be configured to ignore the signal entirely as well. 30 * 31 * The only Super I/O device register we care about is at index 32 * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255). 33 * If set to zero, this disables the watchdog. When set, the system 34 * must periodically (before watchdog expires) clear (set to zero) and 35 * re-set the watchdog else it will trigger. 36 * 37 * There are two other indexed watchdog registers inside this Super I/O 38 * logical device, but they are unused. The first, at index 0x06 is 39 * the watchdog control and can be used to make the watchdog timer re-set 40 * when the PS/2 mouse or serial lines show activity. The second, at 41 * index 0x07 is merely a sampling of the line from the watchdog to the 42 * BBC. 43 * 44 * The watchdog device generates no interrupts. 45 */ 46 47MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); 48MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO"); 49MODULE_SUPPORTED_DEVICE("watchdog"); 50MODULE_LICENSE("GPL"); 51 52#define RIOWD_NAME "pmc" 53#define RIOWD_MINOR 215 54 55static DEFINE_SPINLOCK(riowd_lock); 56 57static void __iomem *bbc_regs; 58static void __iomem *riowd_regs; 59#define WDTO_INDEX 0x05 60 61static int riowd_timeout = 1; /* in minutes */ 62module_param(riowd_timeout, int, 0); 63MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes"); 64 65 66static void riowd_writereg(u8 val, int index) 67{ 68 unsigned long flags; 69 70 spin_lock_irqsave(&riowd_lock, flags); 71 writeb(index, riowd_regs + 0); 72 writeb(val, riowd_regs + 1); 73 spin_unlock_irqrestore(&riowd_lock, flags); 74} 75 76static void riowd_pingtimer(void) 77{ 78 riowd_writereg(riowd_timeout, WDTO_INDEX); 79} 80 81static void riowd_stoptimer(void) 82{ 83 u8 val; 84 85 riowd_writereg(0, WDTO_INDEX); 86 87 val = readb(bbc_regs + BBC_WDACTION); 88 val &= ~BBC_WDACTION_RST; 89 writeb(val, bbc_regs + BBC_WDACTION); 90} 91 92static void riowd_starttimer(void) 93{ 94 u8 val; 95 96 riowd_writereg(riowd_timeout, WDTO_INDEX); 97 98 val = readb(bbc_regs + BBC_WDACTION); 99 val |= BBC_WDACTION_RST; 100 writeb(val, bbc_regs + BBC_WDACTION); 101} 102 103static int riowd_open(struct inode *inode, struct file *filp) 104{ 105 nonseekable_open(inode, filp); 106 return 0; 107} 108 109static int riowd_release(struct inode *inode, struct file *filp) 110{ 111 return 0; 112} 113 114static int riowd_ioctl(struct inode *inode, struct file *filp, 115 unsigned int cmd, unsigned long arg) 116{ 117 static struct watchdog_info info = { 118 WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317" 119 }; 120 void __user *argp = (void __user *)arg; 121 unsigned int options; 122 int new_margin; 123 124 switch (cmd) { 125 case WDIOC_GETSUPPORT: 126 if (copy_to_user(argp, &info, sizeof(info))) 127 return -EFAULT; 128 break; 129 130 case WDIOC_GETSTATUS: 131 case WDIOC_GETBOOTSTATUS: 132 if (put_user(0, (int __user *)argp)) 133 return -EFAULT; 134 break; 135 136 case WDIOC_KEEPALIVE: 137 riowd_pingtimer(); 138 break; 139 140 case WDIOC_SETOPTIONS: 141 if (copy_from_user(&options, argp, sizeof(options))) 142 return -EFAULT; 143 144 if (options & WDIOS_DISABLECARD) 145 riowd_stoptimer(); 146 else if (options & WDIOS_ENABLECARD) 147 riowd_starttimer(); 148 else 149 return -EINVAL; 150 151 break; 152 153 case WDIOC_SETTIMEOUT: 154 if (get_user(new_margin, (int __user *)argp)) 155 return -EFAULT; 156 if ((new_margin < 60) || (new_margin > (255 * 60))) 157 return -EINVAL; 158 riowd_timeout = (new_margin + 59) / 60; 159 riowd_pingtimer(); 160 /* Fall */ 161 162 case WDIOC_GETTIMEOUT: 163 return put_user(riowd_timeout * 60, (int __user *)argp); 164 165 default: 166 return -EINVAL; 167 }; 168 169 return 0; 170} 171 172static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 173{ 174 if (count) { 175 riowd_pingtimer(); 176 return 1; 177 } 178 179 return 0; 180} 181 182static const struct file_operations riowd_fops = { 183 .owner = THIS_MODULE, 184 .ioctl = riowd_ioctl, 185 .open = riowd_open, 186 .write = riowd_write, 187 .release = riowd_release, 188}; 189 190static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops }; 191 192static int __init riowd_bbc_init(void) 193{ 194 struct linux_ebus *ebus = NULL; 195 struct linux_ebus_device *edev = NULL; 196 u8 val; 197 198 for_each_ebus(ebus) { 199 for_each_ebusdev(edev, ebus) { 200 if (!strcmp(edev->ofdev.node->name, "bbc")) 201 goto found_bbc; 202 } 203 } 204 205found_bbc: 206 if (!edev) 207 return -ENODEV; 208 bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE); 209 if (!bbc_regs) 210 return -ENODEV; 211 212 /* Turn it off. */ 213 val = readb(bbc_regs + BBC_WDACTION); 214 val &= ~BBC_WDACTION_RST; 215 writeb(val, bbc_regs + BBC_WDACTION); 216 217 return 0; 218} 219 220static int __init riowd_init(void) 221{ 222 struct linux_ebus *ebus = NULL; 223 struct linux_ebus_device *edev = NULL; 224 225 for_each_ebus(ebus) { 226 for_each_ebusdev(edev, ebus) { 227 if (!strcmp(edev->ofdev.node->name, RIOWD_NAME)) 228 goto ebus_done; 229 } 230 } 231 232ebus_done: 233 if (!edev) 234 goto fail; 235 236 riowd_regs = ioremap(edev->resource[0].start, 2); 237 if (riowd_regs == NULL) { 238 printk(KERN_ERR "pmc: Cannot map registers.\n"); 239 return -ENODEV; 240 } 241 242 if (riowd_bbc_init()) { 243 printk(KERN_ERR "pmc: Failure initializing BBC config.\n"); 244 goto fail; 245 } 246 247 if (misc_register(&riowd_miscdev)) { 248 printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n"); 249 goto fail; 250 } 251 252 printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], " 253 "regs at %p\n", riowd_timeout, riowd_regs); 254 255 return 0; 256 257fail: 258 if (riowd_regs) { 259 iounmap(riowd_regs); 260 riowd_regs = NULL; 261 } 262 if (bbc_regs) { 263 iounmap(bbc_regs); 264 bbc_regs = NULL; 265 } 266 return -ENODEV; 267} 268 269static void __exit riowd_cleanup(void) 270{ 271 misc_deregister(&riowd_miscdev); 272 iounmap(riowd_regs); 273 riowd_regs = NULL; 274 iounmap(bbc_regs); 275 bbc_regs = NULL; 276} 277 278module_init(riowd_init); 279module_exit(riowd_cleanup); 280