Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7cd5b08b authored by Wim Van Sebroeck's avatar Wim Van Sebroeck
Browse files

[WATCHDOG] iTCO_wdt : problem with rebooting on new ICH9 based motherboards



Bugzilla #9868: On Intel motherboards with the ICH9 based I/O controllers
(Like DP35DP and DG33FB) the iTCO timer counts but it doesn't reboot the
system after the counter expires.

This patch fixes this by moving the enabling & disabling of the TCO_EN bit
in the SMI_EN register into the start and stop code.

Signed-off-by: default avatarWim Van Sebroeck <wim@iguana.be>
parent f80e919b
Loading
Loading
Loading
Loading
+4 −27
Original line number Original line Diff line number Diff line
/*
/*
 *	intel TCO vendor specific watchdog driver support
 *	intel TCO vendor specific watchdog driver support
 *
 *
 *	(c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>.
 *	(c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>.
 *
 *
 *	This program is free software; you can redistribute it and/or
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	modify it under the terms of the GNU General Public License
@@ -19,8 +19,7 @@


/* Module and version information */
/* Module and version information */
#define DRV_NAME	"iTCO_vendor_support"
#define DRV_NAME	"iTCO_vendor_support"
#define DRV_VERSION	"1.01"
#define DRV_VERSION	"1.02"
#define DRV_RELDATE	"11-Nov-2006"
#define PFX		DRV_NAME ": "
#define PFX		DRV_NAME ": "


/* Includes */
/* Includes */
@@ -78,24 +77,6 @@ MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (n
 *	    20.6 seconds.
 *	    20.6 seconds.
 */
 */


static void supermicro_old_pre_start(unsigned long acpibase)
{
	unsigned long val32;

	val32 = inl(SMI_EN);
	val32 &= 0xffffdfff;	/* Turn off SMI clearing watchdog */
	outl(val32, SMI_EN);	/* Needed to activate watchdog */
}

static void supermicro_old_pre_stop(unsigned long acpibase)
{
	unsigned long val32;

	val32 = inl(SMI_EN);
	val32 &= 0x00002000;	/* Turn on SMI clearing watchdog */
	outl(val32, SMI_EN);	/* Needed to deactivate watchdog */
}

static void supermicro_old_pre_keepalive(unsigned long acpibase)
static void supermicro_old_pre_keepalive(unsigned long acpibase)
{
{
	/* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
	/* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
@@ -247,18 +228,14 @@ static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
void iTCO_vendor_pre_start(unsigned long acpibase,
void iTCO_vendor_pre_start(unsigned long acpibase,
			   unsigned int heartbeat)
			   unsigned int heartbeat)
{
{
	if (vendorsupport == SUPERMICRO_OLD_BOARD)
	if (vendorsupport == SUPERMICRO_NEW_BOARD)
		supermicro_old_pre_start(acpibase);
	else if (vendorsupport == SUPERMICRO_NEW_BOARD)
		supermicro_new_pre_start(heartbeat);
		supermicro_new_pre_start(heartbeat);
}
}
EXPORT_SYMBOL(iTCO_vendor_pre_start);
EXPORT_SYMBOL(iTCO_vendor_pre_start);


void iTCO_vendor_pre_stop(unsigned long acpibase)
void iTCO_vendor_pre_stop(unsigned long acpibase)
{
{
	if (vendorsupport == SUPERMICRO_OLD_BOARD)
	if (vendorsupport == SUPERMICRO_NEW_BOARD)
		supermicro_old_pre_stop(acpibase);
	else if (vendorsupport == SUPERMICRO_NEW_BOARD)
		supermicro_new_pre_stop();
		supermicro_new_pre_stop();
}
}
EXPORT_SYMBOL(iTCO_vendor_pre_stop);
EXPORT_SYMBOL(iTCO_vendor_pre_stop);
+28 −13
Original line number Original line Diff line number Diff line
/*
/*
 *	intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
 *	intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
 *
 *
 *	(c) Copyright 2006-2007 Wim Van Sebroeck <wim@iguana.be>.
 *	(c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>.
 *
 *
 *	This program is free software; you can redistribute it and/or
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	modify it under the terms of the GNU General Public License
@@ -56,8 +56,7 @@


/* Module and version information */
/* Module and version information */
#define DRV_NAME	"iTCO_wdt"
#define DRV_NAME	"iTCO_wdt"
#define DRV_VERSION	"1.03"
#define DRV_VERSION	"1.04"
#define DRV_RELDATE	"30-Apr-2008"
#define PFX		DRV_NAME ": "
#define PFX		DRV_NAME ": "


/* Includes */
/* Includes */
@@ -311,6 +310,7 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void)
static int iTCO_wdt_start(void)
static int iTCO_wdt_start(void)
{
{
	unsigned int val;
	unsigned int val;
	unsigned long val32;


	spin_lock(&iTCO_wdt_private.io_lock);
	spin_lock(&iTCO_wdt_private.io_lock);


@@ -323,6 +323,18 @@ static int iTCO_wdt_start(void)
		return -EIO;
		return -EIO;
	}
	}


	/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
	val32 = inl(SMI_EN);
	val32 &= 0xffffdfff;	/* Turn off SMI clearing watchdog */
	outl(val32, SMI_EN);

	/* Force the timer to its reload value by writing to the TCO_RLD
	   register */
	if (iTCO_wdt_private.iTCO_version == 2)
		outw(0x01, TCO_RLD);
	else if (iTCO_wdt_private.iTCO_version == 1)
		outb(0x01, TCO_RLD);

	/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
	/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
	val = inw(TCO1_CNT);
	val = inw(TCO1_CNT);
	val &= 0xf7ff;
	val &= 0xf7ff;
@@ -338,6 +350,7 @@ static int iTCO_wdt_start(void)
static int iTCO_wdt_stop(void)
static int iTCO_wdt_stop(void)
{
{
	unsigned int val;
	unsigned int val;
	unsigned long val32;


	spin_lock(&iTCO_wdt_private.io_lock);
	spin_lock(&iTCO_wdt_private.io_lock);


@@ -349,6 +362,11 @@ static int iTCO_wdt_stop(void)
	outw(val, TCO1_CNT);
	outw(val, TCO1_CNT);
	val = inw(TCO1_CNT);
	val = inw(TCO1_CNT);


	/* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
	val32 = inl(SMI_EN);
	val32 &= 0x00002000;
	outl(val32, SMI_EN);

	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
	iTCO_wdt_set_NO_REBOOT_bit();
	iTCO_wdt_set_NO_REBOOT_bit();


@@ -459,7 +477,6 @@ static int iTCO_wdt_open(struct inode *inode, struct file *file)
	/*
	/*
	 *      Reload and activate timer
	 *      Reload and activate timer
	 */
	 */
	iTCO_wdt_keepalive();
	iTCO_wdt_start();
	iTCO_wdt_start();
	return nonseekable_open(inode, file);
	return nonseekable_open(inode, file);
}
}
@@ -604,7 +621,6 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
	int ret;
	int ret;
	u32 base_address;
	u32 base_address;
	unsigned long RCBA;
	unsigned long RCBA;
	unsigned long val32;


	/*
	/*
	 *      Find the ACPI/PM base I/O address which is the base
	 *      Find the ACPI/PM base I/O address which is the base
@@ -644,17 +660,13 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
	iTCO_wdt_set_NO_REBOOT_bit();
	iTCO_wdt_set_NO_REBOOT_bit();


	/* Set the TCO_EN bit in SMI_EN register */
	/* The TCO logic uses the TCO_EN bit in the SMI_EN register */
	if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
	if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
		printk(KERN_ERR PFX
		printk(KERN_ERR PFX
			"I/O address 0x%04lx already in use\n", SMI_EN);
			"I/O address 0x%04lx already in use\n", SMI_EN);
		ret = -EIO;
		ret = -EIO;
		goto out;
		goto out;
	}
	}
	val32 = inl(SMI_EN);
	val32 &= 0xffffdfff;	/* Turn off SMI clearing watchdog */
	outl(val32, SMI_EN);
	release_region(SMI_EN, 4);


	/* The TCO I/O registers reside in a 32-byte range pointed to
	/* The TCO I/O registers reside in a 32-byte range pointed to
	   by the TCOBASE value */
	   by the TCOBASE value */
@@ -662,7 +674,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
		printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
		printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
			TCOBASE);
			TCOBASE);
		ret = -EIO;
		ret = -EIO;
		goto out;
		goto unreg_smi_en;
	}
	}


	printk(KERN_INFO PFX
	printk(KERN_INFO PFX
@@ -701,6 +713,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,


unreg_region:
unreg_region:
	release_region(TCOBASE, 0x20);
	release_region(TCOBASE, 0x20);
unreg_smi_en:
	release_region(SMI_EN, 4);
out:
out:
	if (iTCO_wdt_private.iTCO_version == 2)
	if (iTCO_wdt_private.iTCO_version == 2)
		iounmap(iTCO_wdt_private.gcs);
		iounmap(iTCO_wdt_private.gcs);
@@ -718,6 +732,7 @@ static void __devexit iTCO_wdt_cleanup(void)
	/* Deregister */
	/* Deregister */
	misc_deregister(&iTCO_wdt_miscdev);
	misc_deregister(&iTCO_wdt_miscdev);
	release_region(TCOBASE, 0x20);
	release_region(TCOBASE, 0x20);
	release_region(SMI_EN, 4);
	if (iTCO_wdt_private.iTCO_version == 2)
	if (iTCO_wdt_private.iTCO_version == 2)
		iounmap(iTCO_wdt_private.gcs);
		iounmap(iTCO_wdt_private.gcs);
	pci_dev_put(iTCO_wdt_private.pdev);
	pci_dev_put(iTCO_wdt_private.pdev);
@@ -782,8 +797,8 @@ static int __init iTCO_wdt_init_module(void)
{
{
	int err;
	int err;


	printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s (%s)\n",
	printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
		DRV_VERSION, DRV_RELDATE);
		DRV_VERSION);


	err = platform_driver_register(&iTCO_wdt_driver);
	err = platform_driver_register(&iTCO_wdt_driver);
	if (err)
	if (err)