• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/watchdog/
1/*
2 *	intel TCO Watchdog Driver
3 *
4 *	(c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
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.)
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)
29 *	document number 313056-003, 313057-017: 82801H (ICH8)
30 *	document number 316972-004, 316973-012: 82801I (ICH9)
31 *	document number 319973-002, 319974-002: 82801J (ICH10)
32 *	document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
33 *	document number 320066-003, 320257-008: EP80597 (IICH)
34 *	document number TBD                   : Cougar Point (CPT)
35 */
36
37/*
38 *	Includes, defines, variables, module parameters, ...
39 */
40
41/* Module and version information */
42#define DRV_NAME	"iTCO_wdt"
43#define DRV_VERSION	"1.06"
44#define PFX		DRV_NAME ": "
45
46/* Includes */
47#include <linux/module.h>		/* For module specific items */
48#include <linux/moduleparam.h>		/* For new moduleparam's */
49#include <linux/types.h>		/* For standard types (like size_t) */
50#include <linux/errno.h>		/* For the -ENODEV/... values */
51#include <linux/kernel.h>		/* For printk/panic/... */
52#include <linux/miscdevice.h>		/* For MODULE_ALIAS_MISCDEV
53							(WATCHDOG_MINOR) */
54#include <linux/watchdog.h>		/* For the watchdog specific items */
55#include <linux/init.h>			/* For __init/__exit/... */
56#include <linux/fs.h>			/* For file operations */
57#include <linux/platform_device.h>	/* For platform_driver framework */
58#include <linux/pci.h>			/* For pci functions */
59#include <linux/ioport.h>		/* For io-port access */
60#include <linux/spinlock.h>		/* For spin_lock/spin_unlock/... */
61#include <linux/uaccess.h>		/* For copy_to_user/put_user/... */
62#include <linux/io.h>			/* For inb/outb/... */
63
64#include "iTCO_vendor.h"
65
66/* TCO related info */
67enum iTCO_chipsets {
68	TCO_ICH = 0,	/* ICH */
69	TCO_ICH0,	/* ICH0 */
70	TCO_ICH2,	/* ICH2 */
71	TCO_ICH2M,	/* ICH2-M */
72	TCO_ICH3,	/* ICH3-S */
73	TCO_ICH3M,	/* ICH3-M */
74	TCO_ICH4,	/* ICH4 */
75	TCO_ICH4M,	/* ICH4-M */
76	TCO_CICH,	/* C-ICH */
77	TCO_ICH5,	/* ICH5 & ICH5R */
78	TCO_6300ESB,	/* 6300ESB */
79	TCO_ICH6,	/* ICH6 & ICH6R */
80	TCO_ICH6M,	/* ICH6-M */
81	TCO_ICH6W,	/* ICH6W & ICH6RW */
82	TCO_631XESB,	/* 631xESB/632xESB */
83	TCO_ICH7,	/* ICH7 & ICH7R */
84	TCO_ICH7DH,	/* ICH7DH */
85	TCO_ICH7M,	/* ICH7-M & ICH7-U */
86	TCO_ICH7MDH,	/* ICH7-M DH */
87	TCO_ICH8,	/* ICH8 & ICH8R */
88	TCO_ICH8DH,	/* ICH8DH */
89	TCO_ICH8DO,	/* ICH8DO */
90	TCO_ICH8M,	/* ICH8M */
91	TCO_ICH8ME,	/* ICH8M-E */
92	TCO_ICH9,	/* ICH9 */
93	TCO_ICH9R,	/* ICH9R */
94	TCO_ICH9DH,	/* ICH9DH */
95	TCO_ICH9DO,	/* ICH9DO */
96	TCO_ICH9M,	/* ICH9M */
97	TCO_ICH9ME,	/* ICH9M-E */
98	TCO_ICH10,	/* ICH10 */
99	TCO_ICH10R,	/* ICH10R */
100	TCO_ICH10D,	/* ICH10D */
101	TCO_ICH10DO,	/* ICH10DO */
102	TCO_PCH,	/* PCH Desktop Full Featured */
103	TCO_PCHM,	/* PCH Mobile Full Featured */
104	TCO_P55,	/* P55 */
105	TCO_PM55,	/* PM55 */
106	TCO_H55,	/* H55 */
107	TCO_QM57,	/* QM57 */
108	TCO_H57,	/* H57 */
109	TCO_HM55,	/* HM55 */
110	TCO_Q57,	/* Q57 */
111	TCO_HM57,	/* HM57 */
112	TCO_PCHMSFF,	/* PCH Mobile SFF Full Featured */
113	TCO_QS57,	/* QS57 */
114	TCO_3400,	/* 3400 */
115	TCO_3420,	/* 3420 */
116	TCO_3450,	/* 3450 */
117	TCO_EP80579,	/* EP80579 */
118	TCO_CPT1,	/* Cougar Point */
119	TCO_CPT2,	/* Cougar Point Desktop */
120	TCO_CPT3,	/* Cougar Point Mobile */
121	TCO_CPT4,	/* Cougar Point */
122	TCO_CPT5,	/* Cougar Point */
123	TCO_CPT6,	/* Cougar Point */
124	TCO_CPT7,	/* Cougar Point */
125	TCO_CPT8,	/* Cougar Point */
126	TCO_CPT9,	/* Cougar Point */
127	TCO_CPT10,	/* Cougar Point */
128	TCO_CPT11,	/* Cougar Point */
129	TCO_CPT12,	/* Cougar Point */
130	TCO_CPT13,	/* Cougar Point */
131	TCO_CPT14,	/* Cougar Point */
132	TCO_CPT15,	/* Cougar Point */
133	TCO_CPT16,	/* Cougar Point */
134	TCO_CPT17,	/* Cougar Point */
135	TCO_CPT18,	/* Cougar Point */
136	TCO_CPT19,	/* Cougar Point */
137	TCO_CPT20,	/* Cougar Point */
138	TCO_CPT21,	/* Cougar Point */
139	TCO_CPT22,	/* Cougar Point */
140	TCO_CPT23,	/* Cougar Point */
141	TCO_CPT24,	/* Cougar Point */
142	TCO_CPT25,	/* Cougar Point */
143	TCO_CPT26,	/* Cougar Point */
144	TCO_CPT27,	/* Cougar Point */
145	TCO_CPT28,	/* Cougar Point */
146	TCO_CPT29,	/* Cougar Point */
147	TCO_CPT30,	/* Cougar Point */
148	TCO_CPT31,	/* Cougar Point */
149};
150
151static struct {
152	char *name;
153	unsigned int iTCO_version;
154} iTCO_chipset_info[] __devinitdata = {
155	{"ICH", 1},
156	{"ICH0", 1},
157	{"ICH2", 1},
158	{"ICH2-M", 1},
159	{"ICH3-S", 1},
160	{"ICH3-M", 1},
161	{"ICH4", 1},
162	{"ICH4-M", 1},
163	{"C-ICH", 1},
164	{"ICH5 or ICH5R", 1},
165	{"6300ESB", 1},
166	{"ICH6 or ICH6R", 2},
167	{"ICH6-M", 2},
168	{"ICH6W or ICH6RW", 2},
169	{"631xESB/632xESB", 2},
170	{"ICH7 or ICH7R", 2},
171	{"ICH7DH", 2},
172	{"ICH7-M or ICH7-U", 2},
173	{"ICH7-M DH", 2},
174	{"ICH8 or ICH8R", 2},
175	{"ICH8DH", 2},
176	{"ICH8DO", 2},
177	{"ICH8M", 2},
178	{"ICH8M-E", 2},
179	{"ICH9", 2},
180	{"ICH9R", 2},
181	{"ICH9DH", 2},
182	{"ICH9DO", 2},
183	{"ICH9M", 2},
184	{"ICH9M-E", 2},
185	{"ICH10", 2},
186	{"ICH10R", 2},
187	{"ICH10D", 2},
188	{"ICH10DO", 2},
189	{"PCH Desktop Full Featured", 2},
190	{"PCH Mobile Full Featured", 2},
191	{"P55", 2},
192	{"PM55", 2},
193	{"H55", 2},
194	{"QM57", 2},
195	{"H57", 2},
196	{"HM55", 2},
197	{"Q57", 2},
198	{"HM57", 2},
199	{"PCH Mobile SFF Full Featured", 2},
200	{"QS57", 2},
201	{"3400", 2},
202	{"3420", 2},
203	{"3450", 2},
204	{"EP80579", 2},
205	{"Cougar Point", 2},
206	{"Cougar Point", 2},
207	{"Cougar Point", 2},
208	{"Cougar Point", 2},
209	{"Cougar Point", 2},
210	{"Cougar Point", 2},
211	{"Cougar Point", 2},
212	{"Cougar Point", 2},
213	{"Cougar Point", 2},
214	{"Cougar Point", 2},
215	{"Cougar Point", 2},
216	{"Cougar Point", 2},
217	{"Cougar Point", 2},
218	{"Cougar Point", 2},
219	{"Cougar Point", 2},
220	{"Cougar Point", 2},
221	{"Cougar Point", 2},
222	{"Cougar Point", 2},
223	{"Cougar Point", 2},
224	{"Cougar Point", 2},
225	{"Cougar Point", 2},
226	{"Cougar Point", 2},
227	{"Cougar Point", 2},
228	{"Cougar Point", 2},
229	{"Cougar Point", 2},
230	{"Cougar Point", 2},
231	{"Cougar Point", 2},
232	{"Cougar Point", 2},
233	{"Cougar Point", 2},
234	{"Cougar Point", 2},
235	{"Cougar Point", 2},
236	{NULL, 0}
237};
238
239#define ITCO_PCI_DEVICE(dev, data) 	\
240	.vendor = PCI_VENDOR_ID_INTEL,	\
241	.device = dev,			\
242	.subvendor = PCI_ANY_ID,	\
243	.subdevice = PCI_ANY_ID,	\
244	.class = 0,			\
245	.class_mask = 0,		\
246	.driver_data = data
247
248/*
249 * This data only exists for exporting the supported PCI ids
250 * via MODULE_DEVICE_TABLE.  We do not actually register a
251 * pci_driver, because the I/O Controller Hub has also other
252 * functions that probably will be registered by other drivers.
253 */
254static struct pci_device_id iTCO_wdt_pci_tbl[] = {
255	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0,	TCO_ICH)},
256	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0,	TCO_ICH0)},
257	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0,	TCO_ICH2)},
258	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10,	TCO_ICH2M)},
259	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0,	TCO_ICH3)},
260	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12,	TCO_ICH3M)},
261	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0,	TCO_ICH4)},
262	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12,	TCO_ICH4M)},
263	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0,		TCO_CICH)},
264	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0,	TCO_ICH5)},
265	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1,		TCO_6300ESB)},
266	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0,		TCO_ICH6)},
267	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1,		TCO_ICH6M)},
268	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2,		TCO_ICH6W)},
269	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0,		TCO_631XESB)},
270	{ ITCO_PCI_DEVICE(0x2671,				TCO_631XESB)},
271	{ ITCO_PCI_DEVICE(0x2672,				TCO_631XESB)},
272	{ ITCO_PCI_DEVICE(0x2673,				TCO_631XESB)},
273	{ ITCO_PCI_DEVICE(0x2674,				TCO_631XESB)},
274	{ ITCO_PCI_DEVICE(0x2675,				TCO_631XESB)},
275	{ ITCO_PCI_DEVICE(0x2676,				TCO_631XESB)},
276	{ ITCO_PCI_DEVICE(0x2677,				TCO_631XESB)},
277	{ ITCO_PCI_DEVICE(0x2678,				TCO_631XESB)},
278	{ ITCO_PCI_DEVICE(0x2679,				TCO_631XESB)},
279	{ ITCO_PCI_DEVICE(0x267a,				TCO_631XESB)},
280	{ ITCO_PCI_DEVICE(0x267b,				TCO_631XESB)},
281	{ ITCO_PCI_DEVICE(0x267c,				TCO_631XESB)},
282	{ ITCO_PCI_DEVICE(0x267d,				TCO_631XESB)},
283	{ ITCO_PCI_DEVICE(0x267e,				TCO_631XESB)},
284	{ ITCO_PCI_DEVICE(0x267f,				TCO_631XESB)},
285	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0,		TCO_ICH7)},
286	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30,		TCO_ICH7DH)},
287	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1,		TCO_ICH7M)},
288	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31,		TCO_ICH7MDH)},
289	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0,		TCO_ICH8)},
290	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2,		TCO_ICH8DH)},
291	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3,		TCO_ICH8DO)},
292	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4,		TCO_ICH8M)},
293	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1,		TCO_ICH8ME)},
294	{ ITCO_PCI_DEVICE(0x2918,				TCO_ICH9)},
295	{ ITCO_PCI_DEVICE(0x2916,				TCO_ICH9R)},
296	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2,		TCO_ICH9DH)},
297	{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4,		TCO_ICH9DO)},
298	{ ITCO_PCI_DEVICE(0x2919,				TCO_ICH9M)},
299	{ ITCO_PCI_DEVICE(0x2917,				TCO_ICH9ME)},
300	{ ITCO_PCI_DEVICE(0x3a18,				TCO_ICH10)},
301	{ ITCO_PCI_DEVICE(0x3a16,				TCO_ICH10R)},
302	{ ITCO_PCI_DEVICE(0x3a1a,				TCO_ICH10D)},
303	{ ITCO_PCI_DEVICE(0x3a14,				TCO_ICH10DO)},
304	{ ITCO_PCI_DEVICE(0x3b00,				TCO_PCH)},
305	{ ITCO_PCI_DEVICE(0x3b01,				TCO_PCHM)},
306	{ ITCO_PCI_DEVICE(0x3b02,				TCO_P55)},
307	{ ITCO_PCI_DEVICE(0x3b03,				TCO_PM55)},
308	{ ITCO_PCI_DEVICE(0x3b06,				TCO_H55)},
309	{ ITCO_PCI_DEVICE(0x3b07,				TCO_QM57)},
310	{ ITCO_PCI_DEVICE(0x3b08,				TCO_H57)},
311	{ ITCO_PCI_DEVICE(0x3b09,				TCO_HM55)},
312	{ ITCO_PCI_DEVICE(0x3b0a,				TCO_Q57)},
313	{ ITCO_PCI_DEVICE(0x3b0b,				TCO_HM57)},
314	{ ITCO_PCI_DEVICE(0x3b0d,				TCO_PCHMSFF)},
315	{ ITCO_PCI_DEVICE(0x3b0f,				TCO_QS57)},
316	{ ITCO_PCI_DEVICE(0x3b12,				TCO_3400)},
317	{ ITCO_PCI_DEVICE(0x3b14,				TCO_3420)},
318	{ ITCO_PCI_DEVICE(0x3b16,				TCO_3450)},
319	{ ITCO_PCI_DEVICE(0x5031,				TCO_EP80579)},
320	{ ITCO_PCI_DEVICE(0x1c41,				TCO_CPT1)},
321	{ ITCO_PCI_DEVICE(0x1c42,				TCO_CPT2)},
322	{ ITCO_PCI_DEVICE(0x1c43,				TCO_CPT3)},
323	{ ITCO_PCI_DEVICE(0x1c44,				TCO_CPT4)},
324	{ ITCO_PCI_DEVICE(0x1c45,				TCO_CPT5)},
325	{ ITCO_PCI_DEVICE(0x1c46,				TCO_CPT6)},
326	{ ITCO_PCI_DEVICE(0x1c47,				TCO_CPT7)},
327	{ ITCO_PCI_DEVICE(0x1c48,				TCO_CPT8)},
328	{ ITCO_PCI_DEVICE(0x1c49,				TCO_CPT9)},
329	{ ITCO_PCI_DEVICE(0x1c4a,				TCO_CPT10)},
330	{ ITCO_PCI_DEVICE(0x1c4b,				TCO_CPT11)},
331	{ ITCO_PCI_DEVICE(0x1c4c,				TCO_CPT12)},
332	{ ITCO_PCI_DEVICE(0x1c4d,				TCO_CPT13)},
333	{ ITCO_PCI_DEVICE(0x1c4e,				TCO_CPT14)},
334	{ ITCO_PCI_DEVICE(0x1c4f,				TCO_CPT15)},
335	{ ITCO_PCI_DEVICE(0x1c50,				TCO_CPT16)},
336	{ ITCO_PCI_DEVICE(0x1c51,				TCO_CPT17)},
337	{ ITCO_PCI_DEVICE(0x1c52,				TCO_CPT18)},
338	{ ITCO_PCI_DEVICE(0x1c53,				TCO_CPT19)},
339	{ ITCO_PCI_DEVICE(0x1c54,				TCO_CPT20)},
340	{ ITCO_PCI_DEVICE(0x1c55,				TCO_CPT21)},
341	{ ITCO_PCI_DEVICE(0x1c56,				TCO_CPT22)},
342	{ ITCO_PCI_DEVICE(0x1c57,				TCO_CPT23)},
343	{ ITCO_PCI_DEVICE(0x1c58,				TCO_CPT24)},
344	{ ITCO_PCI_DEVICE(0x1c59,				TCO_CPT25)},
345	{ ITCO_PCI_DEVICE(0x1c5a,				TCO_CPT26)},
346	{ ITCO_PCI_DEVICE(0x1c5b,				TCO_CPT27)},
347	{ ITCO_PCI_DEVICE(0x1c5c,				TCO_CPT28)},
348	{ ITCO_PCI_DEVICE(0x1c5d,				TCO_CPT29)},
349	{ ITCO_PCI_DEVICE(0x1c5e,				TCO_CPT30)},
350	{ ITCO_PCI_DEVICE(0x1c5f,				TCO_CPT31)},
351	{ 0, },			/* End of list */
352};
353MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
354
355/* Address definitions for the TCO */
356/* TCO base address */
357#define TCOBASE		(iTCO_wdt_private.ACPIBASE + 0x60)
358/* SMI Control and Enable Register */
359#define SMI_EN		(iTCO_wdt_private.ACPIBASE + 0x30)
360
361#define TCO_RLD		(TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */
362#define TCOv1_TMR	(TCOBASE + 0x01) /* TCOv1 Timer Initial Value	*/
363#define TCO_DAT_IN	(TCOBASE + 0x02) /* TCO Data In Register	*/
364#define TCO_DAT_OUT	(TCOBASE + 0x03) /* TCO Data Out Register	*/
365#define TCO1_STS	(TCOBASE + 0x04) /* TCO1 Status Register	*/
366#define TCO2_STS	(TCOBASE + 0x06) /* TCO2 Status Register	*/
367#define TCO1_CNT	(TCOBASE + 0x08) /* TCO1 Control Register	*/
368#define TCO2_CNT	(TCOBASE + 0x0a) /* TCO2 Control Register	*/
369#define TCOv2_TMR	(TCOBASE + 0x12) /* TCOv2 Timer Initial Value	*/
370
371/* internal variables */
372static unsigned long is_active;
373static char expect_release;
374static struct {		/* this is private data for the iTCO_wdt device */
375	/* TCO version/generation */
376	unsigned int iTCO_version;
377	/* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
378	unsigned long ACPIBASE;
379	/* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/
380	unsigned long __iomem *gcs;
381	/* the lock for io operations */
382	spinlock_t io_lock;
383	/* the PCI-device */
384	struct pci_dev *pdev;
385} iTCO_wdt_private;
386
387/* the watchdog platform device */
388static struct platform_device *iTCO_wdt_platform_device;
389
390/* module parameters */
391#define WATCHDOG_HEARTBEAT 30	/* 30 sec default heartbeat */
392static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
393module_param(heartbeat, int, 0);
394MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
395	"5..76 (TCO v1) or 3..614 (TCO v2), default="
396				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
397
398static int nowayout = WATCHDOG_NOWAYOUT;
399module_param(nowayout, int, 0);
400MODULE_PARM_DESC(nowayout,
401	"Watchdog cannot be stopped once started (default="
402				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
403
404/*
405 * Some TCO specific functions
406 */
407
408static inline unsigned int seconds_to_ticks(int seconds)
409{
410	/* the internal timer is stored as ticks which decrement
411	 * every 0.6 seconds */
412	return (seconds * 10) / 6;
413}
414
415static void iTCO_wdt_set_NO_REBOOT_bit(void)
416{
417	u32 val32;
418
419	/* Set the NO_REBOOT bit: this disables reboots */
420	if (iTCO_wdt_private.iTCO_version == 2) {
421		val32 = readl(iTCO_wdt_private.gcs);
422		val32 |= 0x00000020;
423		writel(val32, iTCO_wdt_private.gcs);
424	} else if (iTCO_wdt_private.iTCO_version == 1) {
425		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
426		val32 |= 0x00000002;
427		pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
428	}
429}
430
431static int iTCO_wdt_unset_NO_REBOOT_bit(void)
432{
433	int ret = 0;
434	u32 val32;
435
436	/* Unset the NO_REBOOT bit: this enables reboots */
437	if (iTCO_wdt_private.iTCO_version == 2) {
438		val32 = readl(iTCO_wdt_private.gcs);
439		val32 &= 0xffffffdf;
440		writel(val32, iTCO_wdt_private.gcs);
441
442		val32 = readl(iTCO_wdt_private.gcs);
443		if (val32 & 0x00000020)
444			ret = -EIO;
445	} else if (iTCO_wdt_private.iTCO_version == 1) {
446		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
447		val32 &= 0xfffffffd;
448		pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
449
450		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
451		if (val32 & 0x00000002)
452			ret = -EIO;
453	}
454
455	return ret; /* returns: 0 = OK, -EIO = Error */
456}
457
458static int iTCO_wdt_start(void)
459{
460	unsigned int val;
461
462	spin_lock(&iTCO_wdt_private.io_lock);
463
464	iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
465
466	/* disable chipset's NO_REBOOT bit */
467	if (iTCO_wdt_unset_NO_REBOOT_bit()) {
468		spin_unlock(&iTCO_wdt_private.io_lock);
469		printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
470					"reboot disabled by hardware\n");
471		return -EIO;
472	}
473
474	/* Force the timer to its reload value by writing to the TCO_RLD
475	   register */
476	if (iTCO_wdt_private.iTCO_version == 2)
477		outw(0x01, TCO_RLD);
478	else if (iTCO_wdt_private.iTCO_version == 1)
479		outb(0x01, TCO_RLD);
480
481	/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
482	val = inw(TCO1_CNT);
483	val &= 0xf7ff;
484	outw(val, TCO1_CNT);
485	val = inw(TCO1_CNT);
486	spin_unlock(&iTCO_wdt_private.io_lock);
487
488	if (val & 0x0800)
489		return -1;
490	return 0;
491}
492
493static int iTCO_wdt_stop(void)
494{
495	unsigned int val;
496
497	spin_lock(&iTCO_wdt_private.io_lock);
498
499	iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
500
501	/* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
502	val = inw(TCO1_CNT);
503	val |= 0x0800;
504	outw(val, TCO1_CNT);
505	val = inw(TCO1_CNT);
506
507	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
508	iTCO_wdt_set_NO_REBOOT_bit();
509
510	spin_unlock(&iTCO_wdt_private.io_lock);
511
512	if ((val & 0x0800) == 0)
513		return -1;
514	return 0;
515}
516
517static int iTCO_wdt_keepalive(void)
518{
519	spin_lock(&iTCO_wdt_private.io_lock);
520
521	iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
522
523	/* Reload the timer by writing to the TCO Timer Counter register */
524	if (iTCO_wdt_private.iTCO_version == 2)
525		outw(0x01, TCO_RLD);
526	else if (iTCO_wdt_private.iTCO_version == 1) {
527		/* Reset the timeout status bit so that the timer
528		 * needs to count down twice again before rebooting */
529		outw(0x0008, TCO1_STS);	/* write 1 to clear bit */
530
531		outb(0x01, TCO_RLD);
532	}
533
534	spin_unlock(&iTCO_wdt_private.io_lock);
535	return 0;
536}
537
538static int iTCO_wdt_set_heartbeat(int t)
539{
540	unsigned int val16;
541	unsigned char val8;
542	unsigned int tmrval;
543
544	tmrval = seconds_to_ticks(t);
545
546	/* For TCO v1 the timer counts down twice before rebooting */
547	if (iTCO_wdt_private.iTCO_version == 1)
548		tmrval /= 2;
549
550	/* from the specs: */
551	/* "Values of 0h-3h are ignored and should not be attempted" */
552	if (tmrval < 0x04)
553		return -EINVAL;
554	if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
555	    ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
556		return -EINVAL;
557
558	iTCO_vendor_pre_set_heartbeat(tmrval);
559
560	/* Write new heartbeat to watchdog */
561	if (iTCO_wdt_private.iTCO_version == 2) {
562		spin_lock(&iTCO_wdt_private.io_lock);
563		val16 = inw(TCOv2_TMR);
564		val16 &= 0xfc00;
565		val16 |= tmrval;
566		outw(val16, TCOv2_TMR);
567		val16 = inw(TCOv2_TMR);
568		spin_unlock(&iTCO_wdt_private.io_lock);
569
570		if ((val16 & 0x3ff) != tmrval)
571			return -EINVAL;
572	} else if (iTCO_wdt_private.iTCO_version == 1) {
573		spin_lock(&iTCO_wdt_private.io_lock);
574		val8 = inb(TCOv1_TMR);
575		val8 &= 0xc0;
576		val8 |= (tmrval & 0xff);
577		outb(val8, TCOv1_TMR);
578		val8 = inb(TCOv1_TMR);
579		spin_unlock(&iTCO_wdt_private.io_lock);
580
581		if ((val8 & 0x3f) != tmrval)
582			return -EINVAL;
583	}
584
585	heartbeat = t;
586	return 0;
587}
588
589static int iTCO_wdt_get_timeleft(int *time_left)
590{
591	unsigned int val16;
592	unsigned char val8;
593
594	/* read the TCO Timer */
595	if (iTCO_wdt_private.iTCO_version == 2) {
596		spin_lock(&iTCO_wdt_private.io_lock);
597		val16 = inw(TCO_RLD);
598		val16 &= 0x3ff;
599		spin_unlock(&iTCO_wdt_private.io_lock);
600
601		*time_left = (val16 * 6) / 10;
602	} else if (iTCO_wdt_private.iTCO_version == 1) {
603		spin_lock(&iTCO_wdt_private.io_lock);
604		val8 = inb(TCO_RLD);
605		val8 &= 0x3f;
606		if (!(inw(TCO1_STS) & 0x0008))
607			val8 += (inb(TCOv1_TMR) & 0x3f);
608		spin_unlock(&iTCO_wdt_private.io_lock);
609
610		*time_left = (val8 * 6) / 10;
611	} else
612		return -EINVAL;
613	return 0;
614}
615
616/*
617 *	/dev/watchdog handling
618 */
619
620static int iTCO_wdt_open(struct inode *inode, struct file *file)
621{
622	/* /dev/watchdog can only be opened once */
623	if (test_and_set_bit(0, &is_active))
624		return -EBUSY;
625
626	/*
627	 *      Reload and activate timer
628	 */
629	iTCO_wdt_start();
630	return nonseekable_open(inode, file);
631}
632
633static int iTCO_wdt_release(struct inode *inode, struct file *file)
634{
635	/*
636	 *      Shut off the timer.
637	 */
638	if (expect_release == 42) {
639		iTCO_wdt_stop();
640	} else {
641		printk(KERN_CRIT PFX
642			"Unexpected close, not stopping watchdog!\n");
643		iTCO_wdt_keepalive();
644	}
645	clear_bit(0, &is_active);
646	expect_release = 0;
647	return 0;
648}
649
650static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
651			      size_t len, loff_t *ppos)
652{
653	/* See if we got the magic character 'V' and reload the timer */
654	if (len) {
655		if (!nowayout) {
656			size_t i;
657
658			/* note: just in case someone wrote the magic
659			   character five months ago... */
660			expect_release = 0;
661
662			/* scan to see whether or not we got the
663			   magic character */
664			for (i = 0; i != len; i++) {
665				char c;
666				if (get_user(c, data + i))
667					return -EFAULT;
668				if (c == 'V')
669					expect_release = 42;
670			}
671		}
672
673		/* someone wrote to us, we should reload the timer */
674		iTCO_wdt_keepalive();
675	}
676	return len;
677}
678
679static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
680							unsigned long arg)
681{
682	int new_options, retval = -EINVAL;
683	int new_heartbeat;
684	void __user *argp = (void __user *)arg;
685	int __user *p = argp;
686	static const struct watchdog_info ident = {
687		.options =		WDIOF_SETTIMEOUT |
688					WDIOF_KEEPALIVEPING |
689					WDIOF_MAGICCLOSE,
690		.firmware_version =	0,
691		.identity =		DRV_NAME,
692	};
693
694	switch (cmd) {
695	case WDIOC_GETSUPPORT:
696		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
697	case WDIOC_GETSTATUS:
698	case WDIOC_GETBOOTSTATUS:
699		return put_user(0, p);
700
701	case WDIOC_SETOPTIONS:
702	{
703		if (get_user(new_options, p))
704			return -EFAULT;
705
706		if (new_options & WDIOS_DISABLECARD) {
707			iTCO_wdt_stop();
708			retval = 0;
709		}
710		if (new_options & WDIOS_ENABLECARD) {
711			iTCO_wdt_keepalive();
712			iTCO_wdt_start();
713			retval = 0;
714		}
715		return retval;
716	}
717	case WDIOC_KEEPALIVE:
718		iTCO_wdt_keepalive();
719		return 0;
720
721	case WDIOC_SETTIMEOUT:
722	{
723		if (get_user(new_heartbeat, p))
724			return -EFAULT;
725		if (iTCO_wdt_set_heartbeat(new_heartbeat))
726			return -EINVAL;
727		iTCO_wdt_keepalive();
728		/* Fall */
729	}
730	case WDIOC_GETTIMEOUT:
731		return put_user(heartbeat, p);
732	case WDIOC_GETTIMELEFT:
733	{
734		int time_left;
735		if (iTCO_wdt_get_timeleft(&time_left))
736			return -EINVAL;
737		return put_user(time_left, p);
738	}
739	default:
740		return -ENOTTY;
741	}
742}
743
744/*
745 *	Kernel Interfaces
746 */
747
748static const struct file_operations iTCO_wdt_fops = {
749	.owner =		THIS_MODULE,
750	.llseek =		no_llseek,
751	.write =		iTCO_wdt_write,
752	.unlocked_ioctl =	iTCO_wdt_ioctl,
753	.open =			iTCO_wdt_open,
754	.release =		iTCO_wdt_release,
755};
756
757static struct miscdevice iTCO_wdt_miscdev = {
758	.minor =	WATCHDOG_MINOR,
759	.name =		"watchdog",
760	.fops =		&iTCO_wdt_fops,
761};
762
763/*
764 *	Init & exit routines
765 */
766
767static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
768		const struct pci_device_id *ent, struct platform_device *dev)
769{
770	int ret;
771	u32 base_address;
772	unsigned long RCBA;
773	unsigned long val32;
774
775	/*
776	 *      Find the ACPI/PM base I/O address which is the base
777	 *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
778	 *      ACPIBASE is bits [15:7] from 0x40-0x43
779	 */
780	pci_read_config_dword(pdev, 0x40, &base_address);
781	base_address &= 0x0000ff80;
782	if (base_address == 0x00000000) {
783		/* Something's wrong here, ACPIBASE has to be set */
784		printk(KERN_ERR PFX "failed to get TCOBASE address\n");
785		pci_dev_put(pdev);
786		return -ENODEV;
787	}
788	iTCO_wdt_private.iTCO_version =
789			iTCO_chipset_info[ent->driver_data].iTCO_version;
790	iTCO_wdt_private.ACPIBASE = base_address;
791	iTCO_wdt_private.pdev = pdev;
792
793	/* Get the Memory-Mapped GCS register, we need it for the
794	   NO_REBOOT flag (TCO v2). To get access to it you have to
795	   read RCBA from PCI Config space 0xf0 and use it as base.
796	   GCS = RCBA + ICH6_GCS(0x3410). */
797	if (iTCO_wdt_private.iTCO_version == 2) {
798		pci_read_config_dword(pdev, 0xf0, &base_address);
799		if ((base_address & 1) == 0) {
800			printk(KERN_ERR PFX "RCBA is disabled by hardware\n");
801			ret = -ENODEV;
802			goto out;
803		}
804		RCBA = base_address & 0xffffc000;
805		iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4);
806	}
807
808	/* Check chipset's NO_REBOOT bit */
809	if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
810		printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, "
811					"platform may have disabled it\n");
812		ret = -ENODEV;	/* Cannot reset NO_REBOOT bit */
813		goto out_unmap;
814	}
815
816	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
817	iTCO_wdt_set_NO_REBOOT_bit();
818
819	/* The TCO logic uses the TCO_EN bit in the SMI_EN register */
820	if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
821		printk(KERN_ERR PFX
822			"I/O address 0x%04lx already in use\n", SMI_EN);
823		ret = -EIO;
824		goto out_unmap;
825	}
826	/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
827	val32 = inl(SMI_EN);
828	val32 &= 0xffffdfff;	/* Turn off SMI clearing watchdog */
829	outl(val32, SMI_EN);
830
831	/* The TCO I/O registers reside in a 32-byte range pointed to
832	   by the TCOBASE value */
833	if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
834		printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
835			TCOBASE);
836		ret = -EIO;
837		goto unreg_smi_en;
838	}
839
840	printk(KERN_INFO PFX
841		"Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
842			iTCO_chipset_info[ent->driver_data].name,
843			iTCO_chipset_info[ent->driver_data].iTCO_version,
844			TCOBASE);
845
846	/* Clear out the (probably old) status */
847	outw(0x0008, TCO1_STS);	/* Clear the Time Out Status bit */
848	outw(0x0002, TCO2_STS);	/* Clear SECOND_TO_STS bit */
849	outw(0x0004, TCO2_STS);	/* Clear BOOT_STS bit */
850
851	/* Make sure the watchdog is not running */
852	iTCO_wdt_stop();
853
854	/* Check that the heartbeat value is within it's range;
855	   if not reset to the default */
856	if (iTCO_wdt_set_heartbeat(heartbeat)) {
857		iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
858		printk(KERN_INFO PFX
859			"timeout value out of range, using %d\n", heartbeat);
860	}
861
862	ret = misc_register(&iTCO_wdt_miscdev);
863	if (ret != 0) {
864		printk(KERN_ERR PFX
865			"cannot register miscdev on minor=%d (err=%d)\n",
866							WATCHDOG_MINOR, ret);
867		goto unreg_region;
868	}
869
870	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
871							heartbeat, nowayout);
872
873	return 0;
874
875unreg_region:
876	release_region(TCOBASE, 0x20);
877unreg_smi_en:
878	release_region(SMI_EN, 4);
879out_unmap:
880	if (iTCO_wdt_private.iTCO_version == 2)
881		iounmap(iTCO_wdt_private.gcs);
882out:
883	pci_dev_put(iTCO_wdt_private.pdev);
884	iTCO_wdt_private.ACPIBASE = 0;
885	return ret;
886}
887
888static void __devexit iTCO_wdt_cleanup(void)
889{
890	/* Stop the timer before we leave */
891	if (!nowayout)
892		iTCO_wdt_stop();
893
894	/* Deregister */
895	misc_deregister(&iTCO_wdt_miscdev);
896	release_region(TCOBASE, 0x20);
897	release_region(SMI_EN, 4);
898	if (iTCO_wdt_private.iTCO_version == 2)
899		iounmap(iTCO_wdt_private.gcs);
900	pci_dev_put(iTCO_wdt_private.pdev);
901	iTCO_wdt_private.ACPIBASE = 0;
902}
903
904static int __devinit iTCO_wdt_probe(struct platform_device *dev)
905{
906	int ret = -ENODEV;
907	int found = 0;
908	struct pci_dev *pdev = NULL;
909	const struct pci_device_id *ent;
910
911	spin_lock_init(&iTCO_wdt_private.io_lock);
912
913	for_each_pci_dev(pdev) {
914		ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
915		if (ent) {
916			found++;
917			ret = iTCO_wdt_init(pdev, ent, dev);
918			if (!ret)
919				break;
920		}
921	}
922
923	if (!found)
924		printk(KERN_INFO PFX "No card detected\n");
925
926	return ret;
927}
928
929static int __devexit iTCO_wdt_remove(struct platform_device *dev)
930{
931	if (iTCO_wdt_private.ACPIBASE)
932		iTCO_wdt_cleanup();
933
934	return 0;
935}
936
937static void iTCO_wdt_shutdown(struct platform_device *dev)
938{
939	iTCO_wdt_stop();
940}
941
942#define iTCO_wdt_suspend NULL
943#define iTCO_wdt_resume  NULL
944
945static struct platform_driver iTCO_wdt_driver = {
946	.probe          = iTCO_wdt_probe,
947	.remove         = __devexit_p(iTCO_wdt_remove),
948	.shutdown       = iTCO_wdt_shutdown,
949	.suspend        = iTCO_wdt_suspend,
950	.resume         = iTCO_wdt_resume,
951	.driver         = {
952		.owner  = THIS_MODULE,
953		.name   = DRV_NAME,
954	},
955};
956
957static int __init iTCO_wdt_init_module(void)
958{
959	int err;
960
961	printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
962		DRV_VERSION);
963
964	err = platform_driver_register(&iTCO_wdt_driver);
965	if (err)
966		return err;
967
968	iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME,
969								-1, NULL, 0);
970	if (IS_ERR(iTCO_wdt_platform_device)) {
971		err = PTR_ERR(iTCO_wdt_platform_device);
972		goto unreg_platform_driver;
973	}
974
975	return 0;
976
977unreg_platform_driver:
978	platform_driver_unregister(&iTCO_wdt_driver);
979	return err;
980}
981
982static void __exit iTCO_wdt_cleanup_module(void)
983{
984	platform_device_unregister(iTCO_wdt_platform_device);
985	platform_driver_unregister(&iTCO_wdt_driver);
986	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
987}
988
989module_init(iTCO_wdt_init_module);
990module_exit(iTCO_wdt_cleanup_module);
991
992MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
993MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
994MODULE_VERSION(DRV_VERSION);
995MODULE_LICENSE("GPL");
996MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
997