aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/it87_wdt.c
diff options
context:
space:
mode:
authorNat Gurumoorthy <natg@google.com>2011-05-09 14:45:07 -0400
committerWim Van Sebroeck <wim@iguana.be>2011-07-22 04:55:23 -0400
commita134b825608df6382dbcf4fe2c54232ba8f7355f (patch)
tree2e8d11aa67426d64e4084bdbce42a752d5be01ab /drivers/watchdog/it87_wdt.c
parent02f8c6aee8df3cdc935e9bdd4f2d020306035dbe (diff)
watchdog: Use "request_muxed_region" in it87 watchdog drivers
Changes the it87 watchdog drivers to use "request_muxed_region". Serialize access to the hardware by using "request_muxed_region" macro defined by Alan Cox. Call to this macro will hold off the requestor if the resource is currently busy. The use of the above macro makes it possible to get rid of spinlocks in it8712f_wdt.c and it87_wdt.c watchdog drivers. This also greatly simplifies the implementation of it87_wdt.c driver. "superio_enter" will return an error if call to "request_muxed_region" fails. Rest of the code change is to ripple an error return from superio_enter to the top level. Signed-off-by: Nat Gurumoorthy <natg@google.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog/it87_wdt.c')
-rw-r--r--drivers/watchdog/it87_wdt.c168
1 files changed, 90 insertions, 78 deletions
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index b1bc72f9a20..a2d9a1266a2 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -137,7 +137,6 @@
137 137
138static unsigned int base, gpact, ciract, max_units, chip_type; 138static unsigned int base, gpact, ciract, max_units, chip_type;
139static unsigned long wdt_status; 139static unsigned long wdt_status;
140static DEFINE_SPINLOCK(spinlock);
141 140
142static int nogameport = DEFAULT_NOGAMEPORT; 141static int nogameport = DEFAULT_NOGAMEPORT;
143static int exclusive = DEFAULT_EXCLUSIVE; 142static int exclusive = DEFAULT_EXCLUSIVE;
@@ -163,18 +162,26 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
163 162
164/* Superio Chip */ 163/* Superio Chip */
165 164
166static inline void superio_enter(void) 165static inline int superio_enter(void)
167{ 166{
167 /*
168 * Try to reserve REG and REG + 1 for exclusive access.
169 */
170 if (!request_muxed_region(REG, 2, WATCHDOG_NAME))
171 return -EBUSY;
172
168 outb(0x87, REG); 173 outb(0x87, REG);
169 outb(0x01, REG); 174 outb(0x01, REG);
170 outb(0x55, REG); 175 outb(0x55, REG);
171 outb(0x55, REG); 176 outb(0x55, REG);
177 return 0;
172} 178}
173 179
174static inline void superio_exit(void) 180static inline void superio_exit(void)
175{ 181{
176 outb(0x02, REG); 182 outb(0x02, REG);
177 outb(0x02, VAL); 183 outb(0x02, VAL);
184 release_region(REG, 2);
178} 185}
179 186
180static inline void superio_select(int ldn) 187static inline void superio_select(int ldn)
@@ -255,12 +262,11 @@ static void wdt_keepalive(void)
255 set_bit(WDTS_KEEPALIVE, &wdt_status); 262 set_bit(WDTS_KEEPALIVE, &wdt_status);
256} 263}
257 264
258static void wdt_start(void) 265static int wdt_start(void)
259{ 266{
260 unsigned long flags; 267 int ret = superio_enter();
261 268 if (ret)
262 spin_lock_irqsave(&spinlock, flags); 269 return ret;
263 superio_enter();
264 270
265 superio_select(GPIO); 271 superio_select(GPIO);
266 if (test_bit(WDTS_USE_GP, &wdt_status)) 272 if (test_bit(WDTS_USE_GP, &wdt_status))
@@ -270,15 +276,15 @@ static void wdt_start(void)
270 wdt_update_timeout(); 276 wdt_update_timeout();
271 277
272 superio_exit(); 278 superio_exit();
273 spin_unlock_irqrestore(&spinlock, flags); 279
280 return 0;
274} 281}
275 282
276static void wdt_stop(void) 283static int wdt_stop(void)
277{ 284{
278 unsigned long flags; 285 int ret = superio_enter();
279 286 if (ret)
280 spin_lock_irqsave(&spinlock, flags); 287 return ret;
281 superio_enter();
282 288
283 superio_select(GPIO); 289 superio_select(GPIO);
284 superio_outb(0x00, WDTCTRL); 290 superio_outb(0x00, WDTCTRL);
@@ -288,7 +294,7 @@ static void wdt_stop(void)
288 superio_outb(0x00, WDTVALMSB); 294 superio_outb(0x00, WDTVALMSB);
289 295
290 superio_exit(); 296 superio_exit();
291 spin_unlock_irqrestore(&spinlock, flags); 297 return 0;
292} 298}
293 299
294/** 300/**
@@ -303,8 +309,6 @@ static void wdt_stop(void)
303 309
304static int wdt_set_timeout(int t) 310static int wdt_set_timeout(int t)
305{ 311{
306 unsigned long flags;
307
308 if (t < 1 || t > max_units * 60) 312 if (t < 1 || t > max_units * 60)
309 return -EINVAL; 313 return -EINVAL;
310 314
@@ -313,14 +317,15 @@ static int wdt_set_timeout(int t)
313 else 317 else
314 timeout = t; 318 timeout = t;
315 319
316 spin_lock_irqsave(&spinlock, flags);
317 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 320 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
318 superio_enter(); 321 int ret = superio_enter();
322 if (ret)
323 return ret;
324
319 superio_select(GPIO); 325 superio_select(GPIO);
320 wdt_update_timeout(); 326 wdt_update_timeout();
321 superio_exit(); 327 superio_exit();
322 } 328 }
323 spin_unlock_irqrestore(&spinlock, flags);
324 return 0; 329 return 0;
325} 330}
326 331
@@ -339,12 +344,12 @@ static int wdt_set_timeout(int t)
339 344
340static int wdt_get_status(int *status) 345static int wdt_get_status(int *status)
341{ 346{
342 unsigned long flags;
343
344 *status = 0; 347 *status = 0;
345 if (testmode) { 348 if (testmode) {
346 spin_lock_irqsave(&spinlock, flags); 349 int ret = superio_enter();
347 superio_enter(); 350 if (ret)
351 return ret;
352
348 superio_select(GPIO); 353 superio_select(GPIO);
349 if (superio_inb(WDTCTRL) & WDT_ZERO) { 354 if (superio_inb(WDTCTRL) & WDT_ZERO) {
350 superio_outb(0x00, WDTCTRL); 355 superio_outb(0x00, WDTCTRL);
@@ -353,7 +358,6 @@ static int wdt_get_status(int *status)
353 } 358 }
354 359
355 superio_exit(); 360 superio_exit();
356 spin_unlock_irqrestore(&spinlock, flags);
357 } 361 }
358 if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status)) 362 if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
359 *status |= WDIOF_KEEPALIVEPING; 363 *status |= WDIOF_KEEPALIVEPING;
@@ -379,9 +383,17 @@ static int wdt_open(struct inode *inode, struct file *file)
379 if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status)) 383 if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
380 return -EBUSY; 384 return -EBUSY;
381 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) { 385 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
386 int ret;
382 if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status)) 387 if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
383 __module_get(THIS_MODULE); 388 __module_get(THIS_MODULE);
384 wdt_start(); 389
390 ret = wdt_start();
391 if (ret) {
392 clear_bit(WDTS_LOCKED, &wdt_status);
393 clear_bit(WDTS_TIMER_RUN, &wdt_status);
394 clear_bit(WDTS_DEV_OPEN, &wdt_status);
395 return ret;
396 }
385 } 397 }
386 return nonseekable_open(inode, file); 398 return nonseekable_open(inode, file);
387} 399}
@@ -403,7 +415,16 @@ static int wdt_release(struct inode *inode, struct file *file)
403{ 415{
404 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 416 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
405 if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) { 417 if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
406 wdt_stop(); 418 int ret = wdt_stop();
419 if (ret) {
420 /*
421 * Stop failed. Just keep the watchdog alive
422 * and hope nothing bad happens.
423 */
424 set_bit(WDTS_EXPECTED, &wdt_status);
425 wdt_keepalive();
426 return ret;
427 }
407 clear_bit(WDTS_TIMER_RUN, &wdt_status); 428 clear_bit(WDTS_TIMER_RUN, &wdt_status);
408 } else { 429 } else {
409 wdt_keepalive(); 430 wdt_keepalive();
@@ -484,7 +505,9 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
484 &ident, sizeof(ident)) ? -EFAULT : 0; 505 &ident, sizeof(ident)) ? -EFAULT : 0;
485 506
486 case WDIOC_GETSTATUS: 507 case WDIOC_GETSTATUS:
487 wdt_get_status(&status); 508 rc = wdt_get_status(&status);
509 if (rc)
510 return rc;
488 return put_user(status, uarg.i); 511 return put_user(status, uarg.i);
489 512
490 case WDIOC_GETBOOTSTATUS: 513 case WDIOC_GETBOOTSTATUS:
@@ -500,14 +523,22 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
500 523
501 switch (new_options) { 524 switch (new_options) {
502 case WDIOS_DISABLECARD: 525 case WDIOS_DISABLECARD:
503 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) 526 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
504 wdt_stop(); 527 rc = wdt_stop();
528 if (rc)
529 return rc;
530 }
505 clear_bit(WDTS_TIMER_RUN, &wdt_status); 531 clear_bit(WDTS_TIMER_RUN, &wdt_status);
506 return 0; 532 return 0;
507 533
508 case WDIOS_ENABLECARD: 534 case WDIOS_ENABLECARD:
509 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) 535 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
510 wdt_start(); 536 rc = wdt_start();
537 if (rc) {
538 clear_bit(WDTS_TIMER_RUN, &wdt_status);
539 return rc;
540 }
541 }
511 return 0; 542 return 0;
512 543
513 default: 544 default:
@@ -560,16 +591,17 @@ static int __init it87_wdt_init(void)
560 int rc = 0; 591 int rc = 0;
561 int try_gameport = !nogameport; 592 int try_gameport = !nogameport;
562 u8 chip_rev; 593 u8 chip_rev;
563 unsigned long flags; 594 int gp_rreq_fail = 0;
564 595
565 wdt_status = 0; 596 wdt_status = 0;
566 597
567 spin_lock_irqsave(&spinlock, flags); 598 rc = superio_enter();
568 superio_enter(); 599 if (rc)
600 return rc;
601
569 chip_type = superio_inw(CHIPID); 602 chip_type = superio_inw(CHIPID);
570 chip_rev = superio_inb(CHIPREV) & 0x0f; 603 chip_rev = superio_inb(CHIPREV) & 0x0f;
571 superio_exit(); 604 superio_exit();
572 spin_unlock_irqrestore(&spinlock, flags);
573 605
574 switch (chip_type) { 606 switch (chip_type) {
575 case IT8702_ID: 607 case IT8702_ID:
@@ -603,8 +635,9 @@ static int __init it87_wdt_init(void)
603 return -ENODEV; 635 return -ENODEV;
604 } 636 }
605 637
606 spin_lock_irqsave(&spinlock, flags); 638 rc = superio_enter();
607 superio_enter(); 639 if (rc)
640 return rc;
608 641
609 superio_select(GPIO); 642 superio_select(GPIO);
610 superio_outb(WDT_TOV1, WDTCFG); 643 superio_outb(WDT_TOV1, WDTCFG);
@@ -620,21 +653,16 @@ static int __init it87_wdt_init(void)
620 } 653 }
621 gpact = superio_inb(ACTREG); 654 gpact = superio_inb(ACTREG);
622 superio_outb(0x01, ACTREG); 655 superio_outb(0x01, ACTREG);
623 superio_exit();
624 spin_unlock_irqrestore(&spinlock, flags);
625 if (request_region(base, 1, WATCHDOG_NAME)) 656 if (request_region(base, 1, WATCHDOG_NAME))
626 set_bit(WDTS_USE_GP, &wdt_status); 657 set_bit(WDTS_USE_GP, &wdt_status);
627 else 658 else
628 rc = -EIO; 659 gp_rreq_fail = 1;
629 } else {
630 superio_exit();
631 spin_unlock_irqrestore(&spinlock, flags);
632 } 660 }
633 661
634 /* If we haven't Gameport support, try to get CIR support */ 662 /* If we haven't Gameport support, try to get CIR support */
635 if (!test_bit(WDTS_USE_GP, &wdt_status)) { 663 if (!test_bit(WDTS_USE_GP, &wdt_status)) {
636 if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) { 664 if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
637 if (rc == -EIO) 665 if (gp_rreq_fail)
638 printk(KERN_ERR PFX 666 printk(KERN_ERR PFX
639 "I/O Address 0x%04x and 0x%04x" 667 "I/O Address 0x%04x and 0x%04x"
640 " already in use\n", base, CIR_BASE); 668 " already in use\n", base, CIR_BASE);
@@ -646,21 +674,16 @@ static int __init it87_wdt_init(void)
646 goto err_out; 674 goto err_out;
647 } 675 }
648 base = CIR_BASE; 676 base = CIR_BASE;
649 spin_lock_irqsave(&spinlock, flags);
650 superio_enter();
651 677
652 superio_select(CIR); 678 superio_select(CIR);
653 superio_outw(base, BASEREG); 679 superio_outw(base, BASEREG);
654 superio_outb(0x00, CIR_ILS); 680 superio_outb(0x00, CIR_ILS);
655 ciract = superio_inb(ACTREG); 681 ciract = superio_inb(ACTREG);
656 superio_outb(0x01, ACTREG); 682 superio_outb(0x01, ACTREG);
657 if (rc == -EIO) { 683 if (gp_rreq_fail) {
658 superio_select(GAMEPORT); 684 superio_select(GAMEPORT);
659 superio_outb(gpact, ACTREG); 685 superio_outb(gpact, ACTREG);
660 } 686 }
661
662 superio_exit();
663 spin_unlock_irqrestore(&spinlock, flags);
664 } 687 }
665 688
666 if (timeout < 1 || timeout > max_units * 60) { 689 if (timeout < 1 || timeout > max_units * 60) {
@@ -704,6 +727,7 @@ static int __init it87_wdt_init(void)
704 "nogameport=%d)\n", chip_type, chip_rev, timeout, 727 "nogameport=%d)\n", chip_type, chip_rev, timeout,
705 nowayout, testmode, exclusive, nogameport); 728 nowayout, testmode, exclusive, nogameport);
706 729
730 superio_exit();
707 return 0; 731 return 0;
708 732
709err_out_reboot: 733err_out_reboot:
@@ -711,49 +735,37 @@ err_out_reboot:
711err_out_region: 735err_out_region:
712 release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); 736 release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
713 if (!test_bit(WDTS_USE_GP, &wdt_status)) { 737 if (!test_bit(WDTS_USE_GP, &wdt_status)) {
714 spin_lock_irqsave(&spinlock, flags);
715 superio_enter();
716 superio_select(CIR); 738 superio_select(CIR);
717 superio_outb(ciract, ACTREG); 739 superio_outb(ciract, ACTREG);
718 superio_exit();
719 spin_unlock_irqrestore(&spinlock, flags);
720 } 740 }
721err_out: 741err_out:
722 if (try_gameport) { 742 if (try_gameport) {
723 spin_lock_irqsave(&spinlock, flags);
724 superio_enter();
725 superio_select(GAMEPORT); 743 superio_select(GAMEPORT);
726 superio_outb(gpact, ACTREG); 744 superio_outb(gpact, ACTREG);
727 superio_exit();
728 spin_unlock_irqrestore(&spinlock, flags);
729 } 745 }
730 746
747 superio_exit();
731 return rc; 748 return rc;
732} 749}
733 750
734static void __exit it87_wdt_exit(void) 751static void __exit it87_wdt_exit(void)
735{ 752{
736 unsigned long flags; 753 if (superio_enter() == 0) {
737 int nolock; 754 superio_select(GPIO);
738 755 superio_outb(0x00, WDTCTRL);
739 nolock = !spin_trylock_irqsave(&spinlock, flags); 756 superio_outb(0x00, WDTCFG);
740 superio_enter(); 757 superio_outb(0x00, WDTVALLSB);
741 superio_select(GPIO); 758 if (max_units > 255)
742 superio_outb(0x00, WDTCTRL); 759 superio_outb(0x00, WDTVALMSB);
743 superio_outb(0x00, WDTCFG); 760 if (test_bit(WDTS_USE_GP, &wdt_status)) {
744 superio_outb(0x00, WDTVALLSB); 761 superio_select(GAMEPORT);
745 if (max_units > 255) 762 superio_outb(gpact, ACTREG);
746 superio_outb(0x00, WDTVALMSB); 763 } else {
747 if (test_bit(WDTS_USE_GP, &wdt_status)) { 764 superio_select(CIR);
748 superio_select(GAMEPORT); 765 superio_outb(ciract, ACTREG);
749 superio_outb(gpact, ACTREG); 766 }
750 } else { 767 superio_exit();
751 superio_select(CIR);
752 superio_outb(ciract, ACTREG);
753 } 768 }
754 superio_exit();
755 if (!nolock)
756 spin_unlock_irqrestore(&spinlock, flags);
757 769
758 misc_deregister(&wdt_miscdev); 770 misc_deregister(&wdt_miscdev);
759 unregister_reboot_notifier(&wdt_notifier); 771 unregister_reboot_notifier(&wdt_notifier);