From de8cd9a3067e25a860c225f794e6b249b73aa6b1 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 5 Jun 2009 15:13:08 +0400 Subject: [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 CC: Vasily Averin Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/watchdog/iTCO_wdt.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/watchdog') 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, GCS = RCBA + ICH6_GCS(0x3410). */ if (iTCO_wdt_private.iTCO_version == 2) { pci_read_config_dword(pdev, 0xf0, &base_address); + if ((base_address & 1) == 0) { + printk(KERN_ERR PFX "RCBA is disabled by harddware\n"); + ret = -ENODEV; + goto out; + } RCBA = base_address & 0xffffc000; iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4); } @@ -675,7 +680,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, " "reboot disabled by hardware\n"); ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ - goto out; + goto out_unmap; } /* 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, printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", SMI_EN); ret = -EIO; - goto out; + goto out_unmap; } /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ val32 = inl(SMI_EN); @@ -742,9 +747,10 @@ unreg_region: release_region(TCOBASE, 0x20); unreg_smi_en: release_region(SMI_EN, 4); -out: +out_unmap: if (iTCO_wdt_private.iTCO_version == 2) iounmap(iTCO_wdt_private.gcs); +out: pci_dev_put(iTCO_wdt_private.pdev); iTCO_wdt_private.ACPIBASE = 0; return ret; -- cgit v1.2.3