aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis V. Lunev <den@openvz.org>2009-06-05 07:13:08 -0400
committerWim Van Sebroeck <wim@iguana.be>2009-06-18 03:31:44 -0400
commitde8cd9a3067e25a860c225f794e6b249b73aa6b1 (patch)
tree48dd6f028d03fd4595ee3551e57eae35f73cc671
parente73a780272a46e897bd94a4870fd6b6a8655d2d4 (diff)
[WATCHDOG] iTCO_wdt: fix memory corruption when RCBA is disabled by hardware
According to 9.1.33 on p.343 of ICH8.pdf RCBA can be disabled by hardware if bit 0 of RCBA register is not set. Perform correct check for this to prevent memory corruption under some virtual machines where this feature is disabled. Signed-off-by: Denis V. Lunev <den@openvz.org> CC: Vasily Averin <vvs@openvz.org> Signed-off-by: Wim Van Sebroeck <wim@iguana.be> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
-rw-r--r--drivers/watchdog/iTCO_wdt.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 6284961eff5b..6a51edde6ea7 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -666,6 +666,11 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
666 GCS = RCBA + ICH6_GCS(0x3410). */ 666 GCS = RCBA + ICH6_GCS(0x3410). */
667 if (iTCO_wdt_private.iTCO_version == 2) { 667 if (iTCO_wdt_private.iTCO_version == 2) {
668 pci_read_config_dword(pdev, 0xf0, &base_address); 668 pci_read_config_dword(pdev, 0xf0, &base_address);
669 if ((base_address & 1) == 0) {
670 printk(KERN_ERR PFX "RCBA is disabled by harddware\n");
671 ret = -ENODEV;
672 goto out;
673 }
669 RCBA = base_address & 0xffffc000; 674 RCBA = base_address & 0xffffc000;
670 iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4); 675 iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4);
671 } 676 }
@@ -675,7 +680,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
675 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, " 680 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
676 "reboot disabled by hardware\n"); 681 "reboot disabled by hardware\n");
677 ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ 682 ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
678 goto out; 683 goto out_unmap;
679 } 684 }
680 685
681 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ 686 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
@@ -686,7 +691,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
686 printk(KERN_ERR PFX 691 printk(KERN_ERR PFX
687 "I/O address 0x%04lx already in use\n", SMI_EN); 692 "I/O address 0x%04lx already in use\n", SMI_EN);
688 ret = -EIO; 693 ret = -EIO;
689 goto out; 694 goto out_unmap;
690 } 695 }
691 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ 696 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
692 val32 = inl(SMI_EN); 697 val32 = inl(SMI_EN);
@@ -742,9 +747,10 @@ unreg_region:
742 release_region(TCOBASE, 0x20); 747 release_region(TCOBASE, 0x20);
743unreg_smi_en: 748unreg_smi_en:
744 release_region(SMI_EN, 4); 749 release_region(SMI_EN, 4);
745out: 750out_unmap:
746 if (iTCO_wdt_private.iTCO_version == 2) 751 if (iTCO_wdt_private.iTCO_version == 2)
747 iounmap(iTCO_wdt_private.gcs); 752 iounmap(iTCO_wdt_private.gcs);
753out:
748 pci_dev_put(iTCO_wdt_private.pdev); 754 pci_dev_put(iTCO_wdt_private.pdev);
749 iTCO_wdt_private.ACPIBASE = 0; 755 iTCO_wdt_private.ACPIBASE = 0;
750 return ret; 756 return ret;