aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/ibmasr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/ibmasr.c')
-rw-r--r--drivers/watchdog/ibmasr.c151
1 files changed, 88 insertions, 63 deletions
diff --git a/drivers/watchdog/ibmasr.c b/drivers/watchdog/ibmasr.c
index 94155f6136c2..b82405cfb4cd 100644
--- a/drivers/watchdog/ibmasr.c
+++ b/drivers/watchdog/ibmasr.c
@@ -19,9 +19,8 @@
19#include <linux/miscdevice.h> 19#include <linux/miscdevice.h>
20#include <linux/watchdog.h> 20#include <linux/watchdog.h>
21#include <linux/dmi.h> 21#include <linux/dmi.h>
22 22#include <linux/io.h>
23#include <asm/io.h> 23#include <linux/uaccess.h>
24#include <asm/uaccess.h>
25 24
26 25
27enum { 26enum {
@@ -70,10 +69,13 @@ static char asr_expect_close;
70static unsigned int asr_type, asr_base, asr_length; 69static unsigned int asr_type, asr_base, asr_length;
71static unsigned int asr_read_addr, asr_write_addr; 70static unsigned int asr_read_addr, asr_write_addr;
72static unsigned char asr_toggle_mask, asr_disable_mask; 71static unsigned char asr_toggle_mask, asr_disable_mask;
72static spinlock_t asr_lock;
73 73
74static void asr_toggle(void) 74static void __asr_toggle(void)
75{ 75{
76 unsigned char reg = inb(asr_read_addr); 76 unsigned char reg;
77
78 reg = inb(asr_read_addr);
77 79
78 outb(reg & ~asr_toggle_mask, asr_write_addr); 80 outb(reg & ~asr_toggle_mask, asr_write_addr);
79 reg = inb(asr_read_addr); 81 reg = inb(asr_read_addr);
@@ -83,12 +85,21 @@ static void asr_toggle(void)
83 85
84 outb(reg & ~asr_toggle_mask, asr_write_addr); 86 outb(reg & ~asr_toggle_mask, asr_write_addr);
85 reg = inb(asr_read_addr); 87 reg = inb(asr_read_addr);
88 spin_unlock(&asr_lock);
89}
90
91static void asr_toggle(void)
92{
93 spin_lock(&asr_lock);
94 __asr_toggle();
95 spin_unlock(&asr_lock);
86} 96}
87 97
88static void asr_enable(void) 98static void asr_enable(void)
89{ 99{
90 unsigned char reg; 100 unsigned char reg;
91 101
102 spin_lock(&asr_lock);
92 if (asr_type == ASMTYPE_TOPAZ) { 103 if (asr_type == ASMTYPE_TOPAZ) {
93 /* asr_write_addr == asr_read_addr */ 104 /* asr_write_addr == asr_read_addr */
94 reg = inb(asr_read_addr); 105 reg = inb(asr_read_addr);
@@ -99,17 +110,21 @@ static void asr_enable(void)
99 * First make sure the hardware timer is reset by toggling 110 * First make sure the hardware timer is reset by toggling
100 * ASR hardware timer line. 111 * ASR hardware timer line.
101 */ 112 */
102 asr_toggle(); 113 __asr_toggle();
103 114
104 reg = inb(asr_read_addr); 115 reg = inb(asr_read_addr);
105 outb(reg & ~asr_disable_mask, asr_write_addr); 116 outb(reg & ~asr_disable_mask, asr_write_addr);
106 } 117 }
107 reg = inb(asr_read_addr); 118 reg = inb(asr_read_addr);
119 spin_unlock(&asr_lock);
108} 120}
109 121
110static void asr_disable(void) 122static void asr_disable(void)
111{ 123{
112 unsigned char reg = inb(asr_read_addr); 124 unsigned char reg;
125
126 spin_lock(&asr_lock);
127 reg = inb(asr_read_addr);
113 128
114 if (asr_type == ASMTYPE_TOPAZ) 129 if (asr_type == ASMTYPE_TOPAZ)
115 /* asr_write_addr == asr_read_addr */ 130 /* asr_write_addr == asr_read_addr */
@@ -122,6 +137,7 @@ static void asr_disable(void)
122 outb(reg | asr_disable_mask, asr_write_addr); 137 outb(reg | asr_disable_mask, asr_write_addr);
123 } 138 }
124 reg = inb(asr_read_addr); 139 reg = inb(asr_read_addr);
140 spin_unlock(&asr_lock);
125} 141}
126 142
127static int __init asr_get_base_address(void) 143static int __init asr_get_base_address(void)
@@ -133,7 +149,8 @@ static int __init asr_get_base_address(void)
133 149
134 switch (asr_type) { 150 switch (asr_type) {
135 case ASMTYPE_TOPAZ: 151 case ASMTYPE_TOPAZ:
136 /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */ 152 /* SELECT SuperIO CHIP FOR QUERYING
153 (WRITE 0x07 TO BOTH 0x2E and 0x2F) */
137 outb(0x07, 0x2e); 154 outb(0x07, 0x2e);
138 outb(0x07, 0x2f); 155 outb(0x07, 0x2f);
139 156
@@ -154,14 +171,26 @@ static int __init asr_get_base_address(void)
154 171
155 case ASMTYPE_JASPER: 172 case ASMTYPE_JASPER:
156 type = "Jaspers "; 173 type = "Jaspers ";
157 174#if 0
158 /* FIXME: need to use pci_config_lock here, but it's not exported */ 175 u32 r;
176 /* Suggested fix */
177 pdev = pci_get_bus_and_slot(0, DEVFN(0x1f, 0));
178 if (pdev == NULL)
179 return -ENODEV;
180 pci_read_config_dword(pdev, 0x58, &r);
181 asr_base = r & 0xFFFE;
182 pci_dev_put(pdev);
183#else
184 /* FIXME: need to use pci_config_lock here,
185 but it's not exported */
159 186
160/* spin_lock_irqsave(&pci_config_lock, flags);*/ 187/* spin_lock_irqsave(&pci_config_lock, flags);*/
161 188
162 /* Select the SuperIO chip in the PCI I/O port register */ 189 /* Select the SuperIO chip in the PCI I/O port register */
163 outl(0x8000f858, 0xcf8); 190 outl(0x8000f858, 0xcf8);
164 191
192 /* BUS 0, Slot 1F, fnc 0, offset 58 */
193
165 /* 194 /*
166 * Read the base address for the SuperIO chip. 195 * Read the base address for the SuperIO chip.
167 * Only the lower 16 bits are valid, but the address is word 196 * Only the lower 16 bits are valid, but the address is word
@@ -170,7 +199,7 @@ static int __init asr_get_base_address(void)
170 asr_base = inl(0xcfc) & 0xfffe; 199 asr_base = inl(0xcfc) & 0xfffe;
171 200
172/* spin_unlock_irqrestore(&pci_config_lock, flags);*/ 201/* spin_unlock_irqrestore(&pci_config_lock, flags);*/
173 202#endif
174 asr_read_addr = asr_write_addr = 203 asr_read_addr = asr_write_addr =
175 asr_base + JASPER_ASR_REG_OFFSET; 204 asr_base + JASPER_ASR_REG_OFFSET;
176 asr_toggle_mask = JASPER_ASR_TOGGLE_MASK; 205 asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;
@@ -241,66 +270,57 @@ static ssize_t asr_write(struct file *file, const char __user *buf,
241 return count; 270 return count;
242} 271}
243 272
244static int asr_ioctl(struct inode *inode, struct file *file, 273static long asr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
245 unsigned int cmd, unsigned long arg)
246{ 274{
247 static const struct watchdog_info ident = { 275 static const struct watchdog_info ident = {
248 .options = WDIOF_KEEPALIVEPING | 276 .options = WDIOF_KEEPALIVEPING |
249 WDIOF_MAGICCLOSE, 277 WDIOF_MAGICCLOSE,
250 .identity = "IBM ASR" 278 .identity = "IBM ASR",
251 }; 279 };
252 void __user *argp = (void __user *)arg; 280 void __user *argp = (void __user *)arg;
253 int __user *p = argp; 281 int __user *p = argp;
254 int heartbeat; 282 int heartbeat;
255 283
256 switch (cmd) { 284 switch (cmd) {
257 case WDIOC_GETSUPPORT: 285 case WDIOC_GETSUPPORT:
258 return copy_to_user(argp, &ident, sizeof(ident)) ? 286 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
259 -EFAULT : 0; 287 case WDIOC_GETSTATUS:
260 288 case WDIOC_GETBOOTSTATUS:
261 case WDIOC_GETSTATUS: 289 return put_user(0, p);
262 case WDIOC_GETBOOTSTATUS: 290 case WDIOC_SETOPTIONS:
263 return put_user(0, p); 291 {
264 292 int new_options, retval = -EINVAL;
265 case WDIOC_KEEPALIVE: 293 if (get_user(new_options, p))
294 return -EFAULT;
295 if (new_options & WDIOS_DISABLECARD) {
296 asr_disable();
297 retval = 0;
298 }
299 if (new_options & WDIOS_ENABLECARD) {
300 asr_enable();
266 asr_toggle(); 301 asr_toggle();
267 return 0; 302 retval = 0;
268
269 /*
270 * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
271 * and WDIOC_GETTIMEOUT always returns 256.
272 */
273 case WDIOC_GETTIMEOUT:
274 heartbeat = 256;
275 return put_user(heartbeat, p);
276
277 case WDIOC_SETOPTIONS: {
278 int new_options, retval = -EINVAL;
279
280 if (get_user(new_options, p))
281 return -EFAULT;
282
283 if (new_options & WDIOS_DISABLECARD) {
284 asr_disable();
285 retval = 0;
286 }
287
288 if (new_options & WDIOS_ENABLECARD) {
289 asr_enable();
290 asr_toggle();
291 retval = 0;
292 }
293
294 return retval;
295 } 303 }
304 return retval;
305 }
306 case WDIOC_KEEPALIVE:
307 asr_toggle();
308 return 0;
309 /*
310 * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
311 * and WDIOC_GETTIMEOUT always returns 256.
312 */
313 case WDIOC_GETTIMEOUT:
314 heartbeat = 256;
315 return put_user(heartbeat, p);
316 default:
317 return -ENOTTY;
296 } 318 }
297
298 return -ENOTTY;
299} 319}
300 320
301static int asr_open(struct inode *inode, struct file *file) 321static int asr_open(struct inode *inode, struct file *file)
302{ 322{
303 if(test_and_set_bit(0, &asr_is_open)) 323 if (test_and_set_bit(0, &asr_is_open))
304 return -EBUSY; 324 return -EBUSY;
305 325
306 asr_toggle(); 326 asr_toggle();
@@ -314,7 +334,8 @@ static int asr_release(struct inode *inode, struct file *file)
314 if (asr_expect_close == 42) 334 if (asr_expect_close == 42)
315 asr_disable(); 335 asr_disable();
316 else { 336 else {
317 printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); 337 printk(KERN_CRIT PFX
338 "unexpected close, not stopping watchdog!\n");
318 asr_toggle(); 339 asr_toggle();
319 } 340 }
320 clear_bit(0, &asr_is_open); 341 clear_bit(0, &asr_is_open);
@@ -323,12 +344,12 @@ static int asr_release(struct inode *inode, struct file *file)
323} 344}
324 345
325static const struct file_operations asr_fops = { 346static const struct file_operations asr_fops = {
326 .owner = THIS_MODULE, 347 .owner = THIS_MODULE,
327 .llseek = no_llseek, 348 .llseek = no_llseek,
328 .write = asr_write, 349 .write = asr_write,
329 .ioctl = asr_ioctl, 350 .unlocked_ioctl = asr_ioctl,
330 .open = asr_open, 351 .open = asr_open,
331 .release = asr_release, 352 .release = asr_release,
332}; 353};
333 354
334static struct miscdevice asr_miscdev = { 355static struct miscdevice asr_miscdev = {
@@ -367,6 +388,8 @@ static int __init ibmasr_init(void)
367 if (!asr_type) 388 if (!asr_type)
368 return -ENODEV; 389 return -ENODEV;
369 390
391 spin_lock_init(&asr_lock);
392
370 rc = asr_get_base_address(); 393 rc = asr_get_base_address();
371 if (rc) 394 if (rc)
372 return rc; 395 return rc;
@@ -395,7 +418,9 @@ module_init(ibmasr_init);
395module_exit(ibmasr_exit); 418module_exit(ibmasr_exit);
396 419
397module_param(nowayout, int, 0); 420module_param(nowayout, int, 0);
398MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 421MODULE_PARM_DESC(nowayout,
422 "Watchdog cannot be stopped once started (default="
423 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
399 424
400MODULE_DESCRIPTION("IBM Automatic Server Restart driver"); 425MODULE_DESCRIPTION("IBM Automatic Server Restart driver");
401MODULE_AUTHOR("Andrey Panin"); 426MODULE_AUTHOR("Andrey Panin");