| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 1 | /* | 
| Wim Van Sebroeck | cb711a1 | 2009-11-15 13:44:54 +0000 | [diff] [blame] | 2 |  *	intel TCO Watchdog Driver | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 3 |  * | 
| Wim Van Sebroeck | deb9197 | 2011-10-19 23:59:26 +0200 | [diff] [blame] | 4 |  *	(c) Copyright 2006-2011 Wim Van Sebroeck <wim@iguana.be>. | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 5 |  * | 
 | 6 |  *	This program is free software; you can redistribute it and/or | 
 | 7 |  *	modify it under the terms of the GNU General Public License | 
 | 8 |  *	as published by the Free Software Foundation; either version | 
 | 9 |  *	2 of the License, or (at your option) any later version. | 
 | 10 |  * | 
 | 11 |  *	Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor | 
 | 12 |  *	provide warranty for any of this software. This material is | 
 | 13 |  *	provided "AS-IS" and at no charge. | 
 | 14 |  * | 
 | 15 |  *	The TCO watchdog is implemented in the following I/O controller hubs: | 
 | 16 |  *	(See the intel documentation on http://developer.intel.com.) | 
| Wim Van Sebroeck | cb711a1 | 2009-11-15 13:44:54 +0000 | [diff] [blame] | 17 |  *	document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO) | 
 | 18 |  *	document number 290687-002, 298242-027: 82801BA (ICH2) | 
 | 19 |  *	document number 290733-003, 290739-013: 82801CA (ICH3-S) | 
 | 20 |  *	document number 290716-001, 290718-007: 82801CAM (ICH3-M) | 
 | 21 |  *	document number 290744-001, 290745-025: 82801DB (ICH4) | 
 | 22 |  *	document number 252337-001, 252663-008: 82801DBM (ICH4-M) | 
 | 23 |  *	document number 273599-001, 273645-002: 82801E (C-ICH) | 
 | 24 |  *	document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R) | 
 | 25 |  *	document number 300641-004, 300884-013: 6300ESB | 
 | 26 |  *	document number 301473-002, 301474-026: 82801F (ICH6) | 
 | 27 |  *	document number 313082-001, 313075-006: 631xESB, 632xESB | 
 | 28 |  *	document number 307013-003, 307014-024: 82801G (ICH7) | 
| Wim Van Sebroeck | d38bd47 | 2010-12-31 14:10:45 +0000 | [diff] [blame] | 29 |  *	document number 322896-001, 322897-001: NM10 | 
| Wim Van Sebroeck | cb711a1 | 2009-11-15 13:44:54 +0000 | [diff] [blame] | 30 |  *	document number 313056-003, 313057-017: 82801H (ICH8) | 
 | 31 |  *	document number 316972-004, 316973-012: 82801I (ICH9) | 
 | 32 |  *	document number 319973-002, 319974-002: 82801J (ICH10) | 
| Seth Heasley | 3c9d8ec | 2010-01-14 20:58:05 +0000 | [diff] [blame] | 33 |  *	document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) | 
| Imre Kaloz | 4946f83 | 2009-12-07 20:42:26 +0100 | [diff] [blame] | 34 |  *	document number 320066-003, 320257-008: EP80597 (IICH) | 
| Seth Heasley | 203f8d8 | 2011-01-07 17:11:08 -0800 | [diff] [blame] | 35 |  *	document number 324645-001, 324646-001: Cougar Point (CPT) | 
| Seth Heasley | c54fb81 | 2010-11-17 12:15:08 -0700 | [diff] [blame] | 36 |  *	document number TBD                   : Patsburg (PBG) | 
| Seth Heasley | 203f8d8 | 2011-01-07 17:11:08 -0800 | [diff] [blame] | 37 |  *	document number TBD                   : DH89xxCC | 
| Seth Heasley | aa1f465 | 2011-04-20 10:56:20 -0700 | [diff] [blame] | 38 |  *	document number TBD                   : Panther Point | 
| Seth Heasley | 84e83c28 | 2012-01-23 16:40:55 -0800 | [diff] [blame] | 39 |  *	document number TBD                   : Lynx Point | 
| James Ralston | 7fb9c1a | 2012-08-09 09:46:13 -0700 | [diff] [blame] | 40 |  *	document number TBD                   : Lynx Point-LP | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 41 |  */ | 
 | 42 |  | 
 | 43 | /* | 
 | 44 |  *	Includes, defines, variables, module parameters, ... | 
 | 45 |  */ | 
 | 46 |  | 
| Joe Perches | 27c766a | 2012-02-15 15:06:19 -0800 | [diff] [blame] | 47 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 
 | 48 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 49 | /* Module and version information */ | 
| Wim Van Sebroeck | 7944d3a | 2008-08-06 20:19:41 +0000 | [diff] [blame] | 50 | #define DRV_NAME	"iTCO_wdt" | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 51 | #define DRV_VERSION	"1.10" | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 52 |  | 
 | 53 | /* Includes */ | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 54 | #include <linux/module.h>		/* For module specific items */ | 
 | 55 | #include <linux/moduleparam.h>		/* For new moduleparam's */ | 
 | 56 | #include <linux/types.h>		/* For standard types (like size_t) */ | 
 | 57 | #include <linux/errno.h>		/* For the -ENODEV/... values */ | 
 | 58 | #include <linux/kernel.h>		/* For printk/panic/... */ | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 59 | #include <linux/miscdevice.h>		/* For MODULE_ALIAS_MISCDEV | 
 | 60 | 							(WATCHDOG_MINOR) */ | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 61 | #include <linux/watchdog.h>		/* For the watchdog specific items */ | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 62 | #include <linux/init.h>			/* For __init/__exit/... */ | 
 | 63 | #include <linux/fs.h>			/* For file operations */ | 
 | 64 | #include <linux/platform_device.h>	/* For platform_driver framework */ | 
 | 65 | #include <linux/pci.h>			/* For pci functions */ | 
 | 66 | #include <linux/ioport.h>		/* For io-port access */ | 
 | 67 | #include <linux/spinlock.h>		/* For spin_lock/spin_unlock/... */ | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 68 | #include <linux/uaccess.h>		/* For copy_to_user/put_user/... */ | 
 | 69 | #include <linux/io.h>			/* For inb/outb/... */ | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 70 | #include <linux/mfd/core.h> | 
 | 71 | #include <linux/mfd/lpc_ich.h> | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 72 |  | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 73 | #include "iTCO_vendor.h" | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 74 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 75 | /* Address definitions for the TCO */ | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 76 | /* TCO base address */ | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 77 | #define TCOBASE		(iTCO_wdt_private.tco_res->start) | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 78 | /* SMI Control and Enable Register */ | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 79 | #define SMI_EN		(iTCO_wdt_private.smi_res->start) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 80 |  | 
| Wim Van Sebroeck | 0a7e658 | 2009-04-14 20:20:07 +0000 | [diff] [blame] | 81 | #define TCO_RLD		(TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */ | 
 | 82 | #define TCOv1_TMR	(TCOBASE + 0x01) /* TCOv1 Timer Initial Value	*/ | 
 | 83 | #define TCO_DAT_IN	(TCOBASE + 0x02) /* TCO Data In Register	*/ | 
 | 84 | #define TCO_DAT_OUT	(TCOBASE + 0x03) /* TCO Data Out Register	*/ | 
 | 85 | #define TCO1_STS	(TCOBASE + 0x04) /* TCO1 Status Register	*/ | 
 | 86 | #define TCO2_STS	(TCOBASE + 0x06) /* TCO2 Status Register	*/ | 
 | 87 | #define TCO1_CNT	(TCOBASE + 0x08) /* TCO1 Control Register	*/ | 
 | 88 | #define TCO2_CNT	(TCOBASE + 0x0a) /* TCO2 Control Register	*/ | 
 | 89 | #define TCOv2_TMR	(TCOBASE + 0x12) /* TCOv2 Timer Initial Value	*/ | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 90 |  | 
 | 91 | /* internal variables */ | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 92 | static struct {		/* this is private data for the iTCO_wdt device */ | 
 | 93 | 	/* TCO version/generation */ | 
 | 94 | 	unsigned int iTCO_version; | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 95 | 	struct resource *tco_res; | 
 | 96 | 	struct resource *smi_res; | 
 | 97 | 	struct resource *gcs_res; | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 98 | 	/* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/ | 
 | 99 | 	unsigned long __iomem *gcs; | 
 | 100 | 	/* the lock for io operations */ | 
 | 101 | 	spinlock_t io_lock; | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 102 | 	struct platform_device *dev; | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 103 | 	/* the PCI-device */ | 
 | 104 | 	struct pci_dev *pdev; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 105 | } iTCO_wdt_private; | 
 | 106 |  | 
 | 107 | /* module parameters */ | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 108 | #define WATCHDOG_TIMEOUT 30	/* 30 sec default heartbeat */ | 
 | 109 | static int heartbeat = WATCHDOG_TIMEOUT;  /* in seconds */ | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 110 | module_param(heartbeat, int, 0); | 
| Pádraig Brady | 7e6811d | 2010-04-19 13:38:25 +0100 | [diff] [blame] | 111 | MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. " | 
 | 112 | 	"5..76 (TCO v1) or 3..614 (TCO v2), default=" | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 113 | 				__MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 114 |  | 
| Wim Van Sebroeck | 86a1e18 | 2012-03-05 16:51:11 +0100 | [diff] [blame] | 115 | static bool nowayout = WATCHDOG_NOWAYOUT; | 
 | 116 | module_param(nowayout, bool, 0); | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 117 | MODULE_PARM_DESC(nowayout, | 
 | 118 | 	"Watchdog cannot be stopped once started (default=" | 
 | 119 | 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 
| Wim Van Sebroeck | e033351 | 2006-11-12 18:05:09 +0100 | [diff] [blame] | 120 |  | 
| Wim Van Sebroeck | 0d09858 | 2011-12-26 15:23:51 +0100 | [diff] [blame] | 121 | static int turn_SMI_watchdog_clear_off = 1; | 
| Wim Van Sebroeck | deb9197 | 2011-10-19 23:59:26 +0200 | [diff] [blame] | 122 | module_param(turn_SMI_watchdog_clear_off, int, 0); | 
 | 123 | MODULE_PARM_DESC(turn_SMI_watchdog_clear_off, | 
| Wim Van Sebroeck | 0d09858 | 2011-12-26 15:23:51 +0100 | [diff] [blame] | 124 | 	"Turn off SMI clearing watchdog (depends on TCO-version)(default=1)"); | 
| Wim Van Sebroeck | deb9197 | 2011-10-19 23:59:26 +0200 | [diff] [blame] | 125 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 126 | /* | 
 | 127 |  * Some TCO specific functions | 
 | 128 |  */ | 
 | 129 |  | 
 | 130 | static inline unsigned int seconds_to_ticks(int seconds) | 
 | 131 | { | 
 | 132 | 	/* the internal timer is stored as ticks which decrement | 
 | 133 | 	 * every 0.6 seconds */ | 
 | 134 | 	return (seconds * 10) / 6; | 
 | 135 | } | 
 | 136 |  | 
 | 137 | static void iTCO_wdt_set_NO_REBOOT_bit(void) | 
 | 138 | { | 
 | 139 | 	u32 val32; | 
 | 140 |  | 
 | 141 | 	/* Set the NO_REBOOT bit: this disables reboots */ | 
 | 142 | 	if (iTCO_wdt_private.iTCO_version == 2) { | 
 | 143 | 		val32 = readl(iTCO_wdt_private.gcs); | 
 | 144 | 		val32 |= 0x00000020; | 
 | 145 | 		writel(val32, iTCO_wdt_private.gcs); | 
 | 146 | 	} else if (iTCO_wdt_private.iTCO_version == 1) { | 
 | 147 | 		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); | 
 | 148 | 		val32 |= 0x00000002; | 
 | 149 | 		pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); | 
 | 150 | 	} | 
 | 151 | } | 
 | 152 |  | 
 | 153 | static int iTCO_wdt_unset_NO_REBOOT_bit(void) | 
 | 154 | { | 
 | 155 | 	int ret = 0; | 
 | 156 | 	u32 val32; | 
 | 157 |  | 
 | 158 | 	/* Unset the NO_REBOOT bit: this enables reboots */ | 
 | 159 | 	if (iTCO_wdt_private.iTCO_version == 2) { | 
 | 160 | 		val32 = readl(iTCO_wdt_private.gcs); | 
 | 161 | 		val32 &= 0xffffffdf; | 
 | 162 | 		writel(val32, iTCO_wdt_private.gcs); | 
 | 163 |  | 
 | 164 | 		val32 = readl(iTCO_wdt_private.gcs); | 
 | 165 | 		if (val32 & 0x00000020) | 
 | 166 | 			ret = -EIO; | 
 | 167 | 	} else if (iTCO_wdt_private.iTCO_version == 1) { | 
 | 168 | 		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); | 
 | 169 | 		val32 &= 0xfffffffd; | 
 | 170 | 		pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); | 
 | 171 |  | 
 | 172 | 		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); | 
 | 173 | 		if (val32 & 0x00000002) | 
 | 174 | 			ret = -EIO; | 
 | 175 | 	} | 
 | 176 |  | 
 | 177 | 	return ret; /* returns: 0 = OK, -EIO = Error */ | 
 | 178 | } | 
 | 179 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 180 | static int iTCO_wdt_start(struct watchdog_device *wd_dev) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 181 | { | 
 | 182 | 	unsigned int val; | 
 | 183 |  | 
 | 184 | 	spin_lock(&iTCO_wdt_private.io_lock); | 
 | 185 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 186 | 	iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, wd_dev->timeout); | 
| Wim Van Sebroeck | e033351 | 2006-11-12 18:05:09 +0100 | [diff] [blame] | 187 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 188 | 	/* disable chipset's NO_REBOOT bit */ | 
 | 189 | 	if (iTCO_wdt_unset_NO_REBOOT_bit()) { | 
| Roel Kluin | 2ba7d7b | 2007-10-23 03:08:27 +0200 | [diff] [blame] | 190 | 		spin_unlock(&iTCO_wdt_private.io_lock); | 
| Joe Perches | 27c766a | 2012-02-15 15:06:19 -0800 | [diff] [blame] | 191 | 		pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n"); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 192 | 		return -EIO; | 
 | 193 | 	} | 
 | 194 |  | 
| Wim Van Sebroeck | 7cd5b08 | 2008-11-19 19:39:58 +0000 | [diff] [blame] | 195 | 	/* Force the timer to its reload value by writing to the TCO_RLD | 
 | 196 | 	   register */ | 
 | 197 | 	if (iTCO_wdt_private.iTCO_version == 2) | 
 | 198 | 		outw(0x01, TCO_RLD); | 
 | 199 | 	else if (iTCO_wdt_private.iTCO_version == 1) | 
 | 200 | 		outb(0x01, TCO_RLD); | 
 | 201 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 202 | 	/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ | 
 | 203 | 	val = inw(TCO1_CNT); | 
 | 204 | 	val &= 0xf7ff; | 
 | 205 | 	outw(val, TCO1_CNT); | 
 | 206 | 	val = inw(TCO1_CNT); | 
 | 207 | 	spin_unlock(&iTCO_wdt_private.io_lock); | 
 | 208 |  | 
 | 209 | 	if (val & 0x0800) | 
 | 210 | 		return -1; | 
 | 211 | 	return 0; | 
 | 212 | } | 
 | 213 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 214 | static int iTCO_wdt_stop(struct watchdog_device *wd_dev) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 215 | { | 
 | 216 | 	unsigned int val; | 
 | 217 |  | 
 | 218 | 	spin_lock(&iTCO_wdt_private.io_lock); | 
 | 219 |  | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 220 | 	iTCO_vendor_pre_stop(iTCO_wdt_private.smi_res); | 
| Wim Van Sebroeck | e033351 | 2006-11-12 18:05:09 +0100 | [diff] [blame] | 221 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 222 | 	/* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ | 
 | 223 | 	val = inw(TCO1_CNT); | 
 | 224 | 	val |= 0x0800; | 
 | 225 | 	outw(val, TCO1_CNT); | 
 | 226 | 	val = inw(TCO1_CNT); | 
 | 227 |  | 
 | 228 | 	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | 
 | 229 | 	iTCO_wdt_set_NO_REBOOT_bit(); | 
 | 230 |  | 
 | 231 | 	spin_unlock(&iTCO_wdt_private.io_lock); | 
 | 232 |  | 
 | 233 | 	if ((val & 0x0800) == 0) | 
 | 234 | 		return -1; | 
 | 235 | 	return 0; | 
 | 236 | } | 
 | 237 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 238 | static int iTCO_wdt_ping(struct watchdog_device *wd_dev) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 239 | { | 
 | 240 | 	spin_lock(&iTCO_wdt_private.io_lock); | 
 | 241 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 242 | 	iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, wd_dev->timeout); | 
| Wim Van Sebroeck | e033351 | 2006-11-12 18:05:09 +0100 | [diff] [blame] | 243 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 244 | 	/* Reload the timer by writing to the TCO Timer Counter register */ | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 245 | 	if (iTCO_wdt_private.iTCO_version == 2) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 246 | 		outw(0x01, TCO_RLD); | 
| Pádraig Brady | 7e6811d | 2010-04-19 13:38:25 +0100 | [diff] [blame] | 247 | 	else if (iTCO_wdt_private.iTCO_version == 1) { | 
 | 248 | 		/* Reset the timeout status bit so that the timer | 
 | 249 | 		 * needs to count down twice again before rebooting */ | 
 | 250 | 		outw(0x0008, TCO1_STS);	/* write 1 to clear bit */ | 
 | 251 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 252 | 		outb(0x01, TCO_RLD); | 
| Pádraig Brady | 7e6811d | 2010-04-19 13:38:25 +0100 | [diff] [blame] | 253 | 	} | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 254 |  | 
 | 255 | 	spin_unlock(&iTCO_wdt_private.io_lock); | 
 | 256 | 	return 0; | 
 | 257 | } | 
 | 258 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 259 | static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 260 | { | 
 | 261 | 	unsigned int val16; | 
 | 262 | 	unsigned char val8; | 
 | 263 | 	unsigned int tmrval; | 
 | 264 |  | 
 | 265 | 	tmrval = seconds_to_ticks(t); | 
| Pádraig Brady | 7e6811d | 2010-04-19 13:38:25 +0100 | [diff] [blame] | 266 |  | 
 | 267 | 	/* For TCO v1 the timer counts down twice before rebooting */ | 
 | 268 | 	if (iTCO_wdt_private.iTCO_version == 1) | 
 | 269 | 		tmrval /= 2; | 
 | 270 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 271 | 	/* from the specs: */ | 
 | 272 | 	/* "Values of 0h-3h are ignored and should not be attempted" */ | 
 | 273 | 	if (tmrval < 0x04) | 
 | 274 | 		return -EINVAL; | 
 | 275 | 	if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) || | 
 | 276 | 	    ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) | 
 | 277 | 		return -EINVAL; | 
 | 278 |  | 
| Wim Van Sebroeck | e033351 | 2006-11-12 18:05:09 +0100 | [diff] [blame] | 279 | 	iTCO_vendor_pre_set_heartbeat(tmrval); | 
 | 280 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 281 | 	/* Write new heartbeat to watchdog */ | 
 | 282 | 	if (iTCO_wdt_private.iTCO_version == 2) { | 
 | 283 | 		spin_lock(&iTCO_wdt_private.io_lock); | 
 | 284 | 		val16 = inw(TCOv2_TMR); | 
 | 285 | 		val16 &= 0xfc00; | 
 | 286 | 		val16 |= tmrval; | 
 | 287 | 		outw(val16, TCOv2_TMR); | 
 | 288 | 		val16 = inw(TCOv2_TMR); | 
 | 289 | 		spin_unlock(&iTCO_wdt_private.io_lock); | 
 | 290 |  | 
 | 291 | 		if ((val16 & 0x3ff) != tmrval) | 
 | 292 | 			return -EINVAL; | 
 | 293 | 	} else if (iTCO_wdt_private.iTCO_version == 1) { | 
 | 294 | 		spin_lock(&iTCO_wdt_private.io_lock); | 
 | 295 | 		val8 = inb(TCOv1_TMR); | 
 | 296 | 		val8 &= 0xc0; | 
 | 297 | 		val8 |= (tmrval & 0xff); | 
 | 298 | 		outb(val8, TCOv1_TMR); | 
 | 299 | 		val8 = inb(TCOv1_TMR); | 
 | 300 | 		spin_unlock(&iTCO_wdt_private.io_lock); | 
 | 301 |  | 
 | 302 | 		if ((val8 & 0x3f) != tmrval) | 
 | 303 | 			return -EINVAL; | 
 | 304 | 	} | 
 | 305 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 306 | 	wd_dev->timeout = t; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 307 | 	return 0; | 
 | 308 | } | 
 | 309 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 310 | static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 311 | { | 
 | 312 | 	unsigned int val16; | 
 | 313 | 	unsigned char val8; | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 314 | 	unsigned int time_left = 0; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 315 |  | 
 | 316 | 	/* read the TCO Timer */ | 
 | 317 | 	if (iTCO_wdt_private.iTCO_version == 2) { | 
 | 318 | 		spin_lock(&iTCO_wdt_private.io_lock); | 
 | 319 | 		val16 = inw(TCO_RLD); | 
 | 320 | 		val16 &= 0x3ff; | 
 | 321 | 		spin_unlock(&iTCO_wdt_private.io_lock); | 
 | 322 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 323 | 		time_left = (val16 * 6) / 10; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 324 | 	} else if (iTCO_wdt_private.iTCO_version == 1) { | 
 | 325 | 		spin_lock(&iTCO_wdt_private.io_lock); | 
 | 326 | 		val8 = inb(TCO_RLD); | 
 | 327 | 		val8 &= 0x3f; | 
| Pádraig Brady | 7e6811d | 2010-04-19 13:38:25 +0100 | [diff] [blame] | 328 | 		if (!(inw(TCO1_STS) & 0x0008)) | 
 | 329 | 			val8 += (inb(TCOv1_TMR) & 0x3f); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 330 | 		spin_unlock(&iTCO_wdt_private.io_lock); | 
 | 331 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 332 | 		time_left = (val8 * 6) / 10; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 333 | 	} | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 334 | 	return time_left; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 335 | } | 
 | 336 |  | 
 | 337 | /* | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 338 |  *	Kernel Interfaces | 
 | 339 |  */ | 
 | 340 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 341 | static const struct watchdog_info ident = { | 
 | 342 | 	.options =		WDIOF_SETTIMEOUT | | 
 | 343 | 				WDIOF_KEEPALIVEPING | | 
 | 344 | 				WDIOF_MAGICCLOSE, | 
 | 345 | 	.firmware_version =	0, | 
 | 346 | 	.identity =		DRV_NAME, | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 347 | }; | 
 | 348 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 349 | static const struct watchdog_ops iTCO_wdt_ops = { | 
 | 350 | 	.owner =		THIS_MODULE, | 
 | 351 | 	.start =		iTCO_wdt_start, | 
 | 352 | 	.stop = 		iTCO_wdt_stop, | 
 | 353 | 	.ping = 		iTCO_wdt_ping, | 
 | 354 | 	.set_timeout =		iTCO_wdt_set_timeout, | 
 | 355 | 	.get_timeleft =		iTCO_wdt_get_timeleft, | 
 | 356 | }; | 
 | 357 |  | 
 | 358 | static struct watchdog_device iTCO_wdt_watchdog_dev = { | 
 | 359 | 	.info =		&ident, | 
 | 360 | 	.ops = 		&iTCO_wdt_ops, | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 361 | }; | 
 | 362 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 363 | /* | 
 | 364 |  *	Init & exit routines | 
 | 365 |  */ | 
 | 366 |  | 
| Bill Pemberton | 4b12b89 | 2012-11-19 13:26:24 -0500 | [diff] [blame] | 367 | static void iTCO_wdt_cleanup(void) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 368 | { | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 369 | 	/* Stop the timer before we leave */ | 
 | 370 | 	if (!nowayout) | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 371 | 		iTCO_wdt_stop(&iTCO_wdt_watchdog_dev); | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 372 |  | 
 | 373 | 	/* Deregister */ | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 374 | 	watchdog_unregister_device(&iTCO_wdt_watchdog_dev); | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 375 |  | 
 | 376 | 	/* release resources */ | 
 | 377 | 	release_region(iTCO_wdt_private.tco_res->start, | 
 | 378 | 			resource_size(iTCO_wdt_private.tco_res)); | 
 | 379 | 	release_region(iTCO_wdt_private.smi_res->start, | 
 | 380 | 			resource_size(iTCO_wdt_private.smi_res)); | 
 | 381 | 	if (iTCO_wdt_private.iTCO_version == 2) { | 
 | 382 | 		iounmap(iTCO_wdt_private.gcs); | 
 | 383 | 		release_mem_region(iTCO_wdt_private.gcs_res->start, | 
 | 384 | 				resource_size(iTCO_wdt_private.gcs_res)); | 
 | 385 | 	} | 
 | 386 |  | 
 | 387 | 	iTCO_wdt_private.tco_res = NULL; | 
 | 388 | 	iTCO_wdt_private.smi_res = NULL; | 
 | 389 | 	iTCO_wdt_private.gcs_res = NULL; | 
 | 390 | 	iTCO_wdt_private.gcs = NULL; | 
 | 391 | } | 
 | 392 |  | 
| Bill Pemberton | 2d991a1 | 2012-11-19 13:21:41 -0500 | [diff] [blame] | 393 | static int iTCO_wdt_probe(struct platform_device *dev) | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 394 | { | 
 | 395 | 	int ret = -ENODEV; | 
| Wim Van Sebroeck | 12d60e2 | 2009-01-28 20:51:04 +0000 | [diff] [blame] | 396 | 	unsigned long val32; | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 397 | 	struct lpc_ich_info *ich_info = dev->dev.platform_data; | 
 | 398 |  | 
 | 399 | 	if (!ich_info) | 
 | 400 | 		goto out; | 
 | 401 |  | 
 | 402 | 	spin_lock_init(&iTCO_wdt_private.io_lock); | 
 | 403 |  | 
 | 404 | 	iTCO_wdt_private.tco_res = | 
 | 405 | 		platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_TCO); | 
 | 406 | 	if (!iTCO_wdt_private.tco_res) | 
 | 407 | 		goto out; | 
 | 408 |  | 
 | 409 | 	iTCO_wdt_private.smi_res = | 
 | 410 | 		platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_SMI); | 
 | 411 | 	if (!iTCO_wdt_private.smi_res) | 
 | 412 | 		goto out; | 
 | 413 |  | 
 | 414 | 	iTCO_wdt_private.iTCO_version = ich_info->iTCO_version; | 
 | 415 | 	iTCO_wdt_private.dev = dev; | 
 | 416 | 	iTCO_wdt_private.pdev = to_pci_dev(dev->dev.parent); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 417 |  | 
 | 418 | 	/* | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 419 | 	 * Get the Memory-Mapped GCS register, we need it for the | 
 | 420 | 	 * NO_REBOOT flag (TCO v2). | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 421 | 	 */ | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 422 | 	if (iTCO_wdt_private.iTCO_version == 2) { | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 423 | 		iTCO_wdt_private.gcs_res = platform_get_resource(dev, | 
 | 424 | 							IORESOURCE_MEM, | 
 | 425 | 							ICH_RES_MEM_GCS); | 
 | 426 |  | 
 | 427 | 		if (!iTCO_wdt_private.gcs_res) | 
 | 428 | 			goto out; | 
 | 429 |  | 
 | 430 | 		if (!request_mem_region(iTCO_wdt_private.gcs_res->start, | 
 | 431 | 			resource_size(iTCO_wdt_private.gcs_res), dev->name)) { | 
 | 432 | 			ret = -EBUSY; | 
| Denis V. Lunev | de8cd9a | 2009-06-05 15:13:08 +0400 | [diff] [blame] | 433 | 			goto out; | 
 | 434 | 		} | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 435 | 		iTCO_wdt_private.gcs = ioremap(iTCO_wdt_private.gcs_res->start, | 
 | 436 | 			resource_size(iTCO_wdt_private.gcs_res)); | 
 | 437 | 		if (!iTCO_wdt_private.gcs) { | 
 | 438 | 			ret = -EIO; | 
 | 439 | 			goto unreg_gcs; | 
 | 440 | 		} | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 441 | 	} | 
 | 442 |  | 
 | 443 | 	/* Check chipset's NO_REBOOT bit */ | 
| Wim Van Sebroeck | e033351 | 2006-11-12 18:05:09 +0100 | [diff] [blame] | 444 | 	if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { | 
| Joe Perches | 27c766a | 2012-02-15 15:06:19 -0800 | [diff] [blame] | 445 | 		pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n"); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 446 | 		ret = -ENODEV;	/* Cannot reset NO_REBOOT bit */ | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 447 | 		goto unmap_gcs; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 448 | 	} | 
 | 449 |  | 
 | 450 | 	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | 
 | 451 | 	iTCO_wdt_set_NO_REBOOT_bit(); | 
 | 452 |  | 
| Wim Van Sebroeck | 7cd5b08 | 2008-11-19 19:39:58 +0000 | [diff] [blame] | 453 | 	/* The TCO logic uses the TCO_EN bit in the SMI_EN register */ | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 454 | 	if (!request_region(iTCO_wdt_private.smi_res->start, | 
 | 455 | 			resource_size(iTCO_wdt_private.smi_res), dev->name)) { | 
 | 456 | 		pr_err("I/O address 0x%04llx already in use, device disabled\n", | 
| Randy Dunlap | 4b98b32 | 2012-05-14 13:15:20 -0700 | [diff] [blame] | 457 | 		       (u64)SMI_EN); | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 458 | 		ret = -EBUSY; | 
 | 459 | 		goto unmap_gcs; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 460 | 	} | 
| Wim Van Sebroeck | 0d09858 | 2011-12-26 15:23:51 +0100 | [diff] [blame] | 461 | 	if (turn_SMI_watchdog_clear_off >= iTCO_wdt_private.iTCO_version) { | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 462 | 		/* | 
 | 463 | 		 * Bit 13: TCO_EN -> 0 | 
 | 464 | 		 * Disables TCO logic generating an SMI# | 
 | 465 | 		 */ | 
| Wim Van Sebroeck | deb9197 | 2011-10-19 23:59:26 +0200 | [diff] [blame] | 466 | 		val32 = inl(SMI_EN); | 
 | 467 | 		val32 &= 0xffffdfff;	/* Turn off SMI clearing watchdog */ | 
 | 468 | 		outl(val32, SMI_EN); | 
 | 469 | 	} | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 470 |  | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 471 | 	if (!request_region(iTCO_wdt_private.tco_res->start, | 
 | 472 | 			resource_size(iTCO_wdt_private.tco_res), dev->name)) { | 
 | 473 | 		pr_err("I/O address 0x%04llx already in use, device disabled\n", | 
| Randy Dunlap | 4b98b32 | 2012-05-14 13:15:20 -0700 | [diff] [blame] | 474 | 		       (u64)TCOBASE); | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 475 | 		ret = -EBUSY; | 
 | 476 | 		goto unreg_smi; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 477 | 	} | 
 | 478 |  | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 479 | 	pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n", | 
| Randy Dunlap | 4b98b32 | 2012-05-14 13:15:20 -0700 | [diff] [blame] | 480 | 		ich_info->name, ich_info->iTCO_version, (u64)TCOBASE); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 481 |  | 
 | 482 | 	/* Clear out the (probably old) status */ | 
| Pádraig Brady | 7e6811d | 2010-04-19 13:38:25 +0100 | [diff] [blame] | 483 | 	outw(0x0008, TCO1_STS);	/* Clear the Time Out Status bit */ | 
 | 484 | 	outw(0x0002, TCO2_STS);	/* Clear SECOND_TO_STS bit */ | 
 | 485 | 	outw(0x0004, TCO2_STS);	/* Clear BOOT_STS bit */ | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 486 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 487 | 	iTCO_wdt_watchdog_dev.bootstatus = 0; | 
 | 488 | 	iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT; | 
 | 489 | 	watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout); | 
 | 490 | 	iTCO_wdt_watchdog_dev.parent = dev->dev.parent; | 
 | 491 |  | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 492 | 	/* Make sure the watchdog is not running */ | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 493 | 	iTCO_wdt_stop(&iTCO_wdt_watchdog_dev); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 494 |  | 
| Alan Cox | 0e6fa3f | 2008-05-19 14:06:25 +0100 | [diff] [blame] | 495 | 	/* Check that the heartbeat value is within it's range; | 
 | 496 | 	   if not reset to the default */ | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 497 | 	if (iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, heartbeat)) { | 
 | 498 | 		iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, WATCHDOG_TIMEOUT); | 
 | 499 | 		pr_info("timeout value out of range, using %d\n", | 
 | 500 | 			WATCHDOG_TIMEOUT); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 501 | 	} | 
 | 502 |  | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 503 | 	ret = watchdog_register_device(&iTCO_wdt_watchdog_dev); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 504 | 	if (ret != 0) { | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 505 | 		pr_err("cannot register watchdog device (err=%d)\n", ret); | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 506 | 		goto unreg_tco; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 507 | 	} | 
 | 508 |  | 
| Joe Perches | 27c766a | 2012-02-15 15:06:19 -0800 | [diff] [blame] | 509 | 	pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n", | 
 | 510 | 		heartbeat, nowayout); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 511 |  | 
 | 512 | 	return 0; | 
 | 513 |  | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 514 | unreg_tco: | 
 | 515 | 	release_region(iTCO_wdt_private.tco_res->start, | 
 | 516 | 			resource_size(iTCO_wdt_private.tco_res)); | 
 | 517 | unreg_smi: | 
 | 518 | 	release_region(iTCO_wdt_private.smi_res->start, | 
 | 519 | 			resource_size(iTCO_wdt_private.smi_res)); | 
 | 520 | unmap_gcs: | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 521 | 	if (iTCO_wdt_private.iTCO_version == 2) | 
 | 522 | 		iounmap(iTCO_wdt_private.gcs); | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 523 | unreg_gcs: | 
 | 524 | 	if (iTCO_wdt_private.iTCO_version == 2) | 
 | 525 | 		release_mem_region(iTCO_wdt_private.gcs_res->start, | 
 | 526 | 				resource_size(iTCO_wdt_private.gcs_res)); | 
| Denis V. Lunev | de8cd9a | 2009-06-05 15:13:08 +0400 | [diff] [blame] | 527 | out: | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 528 | 	iTCO_wdt_private.tco_res = NULL; | 
 | 529 | 	iTCO_wdt_private.smi_res = NULL; | 
 | 530 | 	iTCO_wdt_private.gcs_res = NULL; | 
 | 531 | 	iTCO_wdt_private.gcs = NULL; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 532 |  | 
| Naga Chumbalkar | ec26985 | 2010-02-09 00:42:02 +0100 | [diff] [blame] | 533 | 	return ret; | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 534 | } | 
 | 535 |  | 
| Bill Pemberton | 4b12b89 | 2012-11-19 13:26:24 -0500 | [diff] [blame] | 536 | static int iTCO_wdt_remove(struct platform_device *dev) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 537 | { | 
| Aaron Sierra | 887c8ec | 2012-04-20 14:14:11 -0500 | [diff] [blame] | 538 | 	if (iTCO_wdt_private.tco_res || iTCO_wdt_private.smi_res) | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 539 | 		iTCO_wdt_cleanup(); | 
 | 540 |  | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 541 | 	return 0; | 
 | 542 | } | 
 | 543 |  | 
 | 544 | static void iTCO_wdt_shutdown(struct platform_device *dev) | 
 | 545 | { | 
| Wim Van Sebroeck | bff2343 | 2012-06-09 14:10:28 +0200 | [diff] [blame] | 546 | 	iTCO_wdt_stop(NULL); | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 547 | } | 
 | 548 |  | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 549 | static struct platform_driver iTCO_wdt_driver = { | 
 | 550 | 	.probe          = iTCO_wdt_probe, | 
| Bill Pemberton | 8226871 | 2012-11-19 13:21:12 -0500 | [diff] [blame] | 551 | 	.remove         = iTCO_wdt_remove, | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 552 | 	.shutdown       = iTCO_wdt_shutdown, | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 553 | 	.driver         = { | 
 | 554 | 		.owner  = THIS_MODULE, | 
 | 555 | 		.name   = DRV_NAME, | 
 | 556 | 	}, | 
 | 557 | }; | 
 | 558 |  | 
 | 559 | static int __init iTCO_wdt_init_module(void) | 
 | 560 | { | 
 | 561 | 	int err; | 
 | 562 |  | 
| Joe Perches | 27c766a | 2012-02-15 15:06:19 -0800 | [diff] [blame] | 563 | 	pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION); | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 564 |  | 
 | 565 | 	err = platform_driver_register(&iTCO_wdt_driver); | 
 | 566 | 	if (err) | 
 | 567 | 		return err; | 
 | 568 |  | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 569 | 	return 0; | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 570 | } | 
 | 571 |  | 
 | 572 | static void __exit iTCO_wdt_cleanup_module(void) | 
 | 573 | { | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 574 | 	platform_driver_unregister(&iTCO_wdt_driver); | 
| Joe Perches | 27c766a | 2012-02-15 15:06:19 -0800 | [diff] [blame] | 575 | 	pr_info("Watchdog Module Unloaded\n"); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 576 | } | 
 | 577 |  | 
 | 578 | module_init(iTCO_wdt_init_module); | 
 | 579 | module_exit(iTCO_wdt_cleanup_module); | 
 | 580 |  | 
 | 581 | MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); | 
 | 582 | MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver"); | 
| Wim Van Sebroeck | 3836cc0 | 2006-06-30 08:44:53 +0200 | [diff] [blame] | 583 | MODULE_VERSION(DRV_VERSION); | 
| Wim Van Sebroeck | 9e0ea34 | 2006-05-21 14:37:44 +0200 | [diff] [blame] | 584 | MODULE_LICENSE("GPL"); | 
 | 585 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 
| Jan Beulich | e5de32e | 2012-06-22 16:41:00 +0100 | [diff] [blame] | 586 | MODULE_ALIAS("platform:" DRV_NAME); |