Blame view

drivers/watchdog/i6300esb.c 12.9 KB
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
1
  /*
abda5c8bd   David Hardeman   [WATCHDOG] i6300....
2
   *	i6300esb:	Watchdog timer driver for Intel 6300ESB chipset
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
3
4
   *
   *	(c) Copyright 2004 Google Inc.
96de0e252   Jan Engelhardt   Convert files to ...
5
   *	(c) Copyright 2005 David Härdeman <david@2gen.com>
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
6
7
8
9
10
11
   *
   *	This program is free software; you can redistribute it and/or
   *	modify it under the terms of the GNU General Public License
   *	as published by the Free Software Foundation; either version
   *	2 of the License, or (at your option) any later version.
   *
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
12
   *	based on i810-tco.c which is in turn based on softdog.c
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
13
   *
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
14
15
   *	The timer is implemented in the following I/O controller hubs:
   *	(See the intel documentation on http://developer.intel.com.)
0426fd0d8   Wim Van Sebroeck   [WATCHDOG] i6300e...
16
   *	6300ESB chip : document number 300641-004
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
17
18
19
20
   *
   *  2004YYZZ Ross Biro
   *	Initial version 0.01
   *  2004YYZZ Ross Biro
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
21
   *	Version 0.02
96de0e252   Jan Engelhardt   Convert files to ...
22
   *  20050210 David Härdeman <david@2gen.com>
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
23
   *	Ported driver to kernel 2.6
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
24
25
26
27
28
29
30
31
32
33
34
35
36
   */
  
  /*
   *      Includes, defines, variables, module parameters, ...
   */
  
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/fs.h>
  #include <linux/mm.h>
  #include <linux/miscdevice.h>
  #include <linux/watchdog.h>
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
37
38
39
  #include <linux/init.h>
  #include <linux/pci.h>
  #include <linux/ioport.h>
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
40
41
  #include <linux/uaccess.h>
  #include <linux/io.h>
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
42

cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
43
  /* Module and version information */
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
44
  #define ESB_VERSION "0.05"
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
45
46
47
  #define ESB_MODULE_NAME "i6300ESB timer"
  #define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
  #define PFX ESB_MODULE_NAME ": "
abda5c8bd   David Hardeman   [WATCHDOG] i6300....
48
49
50
51
52
  /* PCI configuration registers */
  #define ESB_CONFIG_REG  0x60            /* Config register                   */
  #define ESB_LOCK_REG    0x68            /* WDT lock register                 */
  
  /* Memory mapped registers */
bd4e6c18a   Wim Van Sebroeck   [WATCHDOG] i6300e...
53
54
55
56
  #define ESB_TIMER1_REG (BASEADDR + 0x00)/* Timer1 value after each reset     */
  #define ESB_TIMER2_REG (BASEADDR + 0x04)/* Timer2 value after each reset     */
  #define ESB_GINTSR_REG (BASEADDR + 0x08)/* General Interrupt Status Register */
  #define ESB_RELOAD_REG (BASEADDR + 0x0c)/* Reload register                   */
abda5c8bd   David Hardeman   [WATCHDOG] i6300....
57
58
  
  /* Lock register bits */
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
59
60
61
  #define ESB_WDT_FUNC    (0x01 << 2)   /* Watchdog functionality            */
  #define ESB_WDT_ENABLE  (0x01 << 1)   /* Enable WDT                        */
  #define ESB_WDT_LOCK    (0x01 << 0)   /* Lock (nowayout)                   */
abda5c8bd   David Hardeman   [WATCHDOG] i6300....
62
63
  
  /* Config register bits */
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
64
65
  #define ESB_WDT_REBOOT  (0x01 << 5)   /* Enable reboot on timeout          */
  #define ESB_WDT_FREQ    (0x01 << 2)   /* Decrement frequency               */
39f3be72c   Wim Van Sebroeck   [WATCHDOG] i6300e...
66
  #define ESB_WDT_INTTYPE (0x03 << 0)   /* Interrupt type on timer1 timeout  */
abda5c8bd   David Hardeman   [WATCHDOG] i6300....
67
68
  
  /* Reload register bits */
31838d9da   Wim Van Sebroeck   [WATCHDOG] i6300e...
69
  #define ESB_WDT_TIMEOUT (0x01 << 9)    /* Watchdog timed out                */
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
70
  #define ESB_WDT_RELOAD  (0x01 << 8)    /* prevent timeout                   */
abda5c8bd   David Hardeman   [WATCHDOG] i6300....
71
72
73
74
  
  /* Magic constants */
  #define ESB_UNLOCK1     0x80            /* Step 1 to unlock reset registers  */
  #define ESB_UNLOCK2     0x86            /* Step 2 to unlock reset registers  */
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
75
76
  /* internal variables */
  static void __iomem *BASEADDR;
c7dfd0cca   Alexey Dobriyan   [WATCHDOG] spin_l...
77
  static DEFINE_SPINLOCK(esb_lock); /* Guards the hardware */
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
78
79
80
81
  static unsigned long timer_alive;
  static struct pci_dev *esb_pci;
  static unsigned short triggered; /* The status of the watchdog upon boot */
  static char esb_expect_close;
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
82
83
84
  
  /* We can only use 1 card due to the /dev/watchdog restriction */
  static int cards_found;
0426fd0d8   Wim Van Sebroeck   [WATCHDOG] i6300e...
85

cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
86
  /* module parameters */
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
87
88
  /* 30 sec default heartbeat (1 < heartbeat < 2*1023) */
  #define WATCHDOG_HEARTBEAT 30
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
89
90
  static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
  module_param(heartbeat, int, 0);
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
91
92
93
  MODULE_PARM_DESC(heartbeat,
  		"Watchdog heartbeat in seconds. (1<heartbeat<2046, default="
  				__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
94

811f99916   Naveen Gupta   [WATCHDOG] i6300e...
95
  static int nowayout = WATCHDOG_NOWAYOUT;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
96
  module_param(nowayout, int, 0);
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
97
98
99
  MODULE_PARM_DESC(nowayout,
  		"Watchdog cannot be stopped once started (default="
  				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
100
101
102
103
104
105
106
107
108
109
110
  
  /*
   * Some i6300ESB specific functions
   */
  
  /*
   * Prepare for reloading the timer by unlocking the proper registers.
   * This is performed by first writing 0x80 followed by 0x86 to the
   * reload register. After this the appropriate registers can be written
   * to once before they need to be unlocked again.
   */
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
111
112
  static inline void esb_unlock_registers(void)
  {
39f3be72c   Wim Van Sebroeck   [WATCHDOG] i6300e...
113
114
  	writew(ESB_UNLOCK1, ESB_RELOAD_REG);
  	writew(ESB_UNLOCK2, ESB_RELOAD_REG);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
115
  }
3b9d49eea   Wim Van Sebroeck   [WATCHDOG] i6300e...
116
  static int esb_timer_start(void)
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
117
118
  {
  	u8 val;
3b9d49eea   Wim Van Sebroeck   [WATCHDOG] i6300e...
119
120
121
  	spin_lock(&esb_lock);
  	esb_unlock_registers();
  	writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
122
  	/* Enable or Enable + Lock? */
fc8a9d830   Wim Van Sebroeck   [WATCHDOG] i6300e...
123
  	val = ESB_WDT_ENABLE | (nowayout ? ESB_WDT_LOCK : 0x00);
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
124
  	pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);
3b9d49eea   Wim Van Sebroeck   [WATCHDOG] i6300e...
125
126
  	spin_unlock(&esb_lock);
  	return 0;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
127
128
129
130
131
132
133
134
135
  }
  
  static int esb_timer_stop(void)
  {
  	u8 val;
  
  	spin_lock(&esb_lock);
  	/* First, reset timers as suggested by the docs */
  	esb_unlock_registers();
ce2f50b4a   Naveen Gupta   [WATCHDOG] i6300e...
136
  	writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
137
138
139
140
141
142
  	/* Then disable the WDT */
  	pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0);
  	pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val);
  	spin_unlock(&esb_lock);
  
  	/* Returns 0 if the timer was disabled, non-zero otherwise */
fc8a9d830   Wim Van Sebroeck   [WATCHDOG] i6300e...
143
  	return val & ESB_WDT_ENABLE;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
144
145
146
147
148
149
  }
  
  static void esb_timer_keepalive(void)
  {
  	spin_lock(&esb_lock);
  	esb_unlock_registers();
ce2f50b4a   Naveen Gupta   [WATCHDOG] i6300e...
150
  	writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
151
  	/* FIXME: Do we need to flush anything here? */
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  	spin_unlock(&esb_lock);
  }
  
  static int esb_timer_set_heartbeat(int time)
  {
  	u32 val;
  
  	if (time < 0x1 || time > (2 * 0x03ff))
  		return -EINVAL;
  
  	spin_lock(&esb_lock);
  
  	/* We shift by 9, so if we are passed a value of 1 sec,
  	 * val will be 1 << 9 = 512, then write that to two
  	 * timers => 2 * 512 = 1024 (which is decremented at 1KHz)
  	 */
  	val = time << 9;
  
  	/* Write timer 1 */
  	esb_unlock_registers();
  	writel(val, ESB_TIMER1_REG);
  
  	/* Write timer 2 */
  	esb_unlock_registers();
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
176
  	writel(val, ESB_TIMER2_REG);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
177

0829291ea   Alan Cox   [WATCHDOG 13/57] ...
178
  	/* Reload */
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
179
  	esb_unlock_registers();
ce2f50b4a   Naveen Gupta   [WATCHDOG] i6300e...
180
  	writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
181
182
183
184
185
186
187
188
  
  	/* FIXME: Do we need to flush everything out? */
  
  	/* Done */
  	heartbeat = time;
  	spin_unlock(&esb_lock);
  	return 0;
  }
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
189
  /*
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
190
   *	/dev/watchdog handling
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
191
   */
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
192
  static int esb_open(struct inode *inode, struct file *file)
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
193
  {
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
194
195
196
  	/* /dev/watchdog can only be opened once */
  	if (test_and_set_bit(0, &timer_alive))
  		return -EBUSY;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
197

0829291ea   Alan Cox   [WATCHDOG 13/57] ...
198
  	/* Reload and activate timer */
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
199
  	esb_timer_start();
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
200
201
202
  
  	return nonseekable_open(inode, file);
  }
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
203
  static int esb_release(struct inode *inode, struct file *file)
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
204
  {
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
205
206
207
208
209
210
211
212
213
214
215
216
  	/* Shut off the timer. */
  	if (esb_expect_close == 42)
  		esb_timer_stop();
  	else {
  		printk(KERN_CRIT PFX
  				"Unexpected close, not stopping watchdog!
  ");
  		esb_timer_keepalive();
  	}
  	clear_bit(0, &timer_alive);
  	esb_expect_close = 0;
  	return 0;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
217
  }
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
218
219
  static ssize_t esb_write(struct file *file, const char __user *data,
  			  size_t len, loff_t *ppos)
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
220
221
  {
  	/* See if we got the magic character 'V' and reload the timer */
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
222
  	if (len) {
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
223
224
225
226
227
228
  		if (!nowayout) {
  			size_t i;
  
  			/* note: just in case someone wrote the magic character
  			 * five months ago... */
  			esb_expect_close = 0;
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
229
230
  			/* scan to see whether or not we got the
  			 * magic character */
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
231
232
  			for (i = 0; i != len; i++) {
  				char c;
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
233
  				if (get_user(c, data + i))
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
234
235
236
237
238
239
240
  					return -EFAULT;
  				if (c == 'V')
  					esb_expect_close = 42;
  			}
  		}
  
  		/* someone wrote to us, we should reload the timer */
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
241
  		esb_timer_keepalive();
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
242
243
244
  	}
  	return len;
  }
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
245
  static long esb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
246
247
248
249
250
  {
  	int new_options, retval = -EINVAL;
  	int new_heartbeat;
  	void __user *argp = (void __user *)arg;
  	int __user *p = argp;
42747d712   Wim Van Sebroeck   [WATCHDOG] watchd...
251
  	static const struct watchdog_info ident = {
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
252
  		.options =		WDIOF_SETTIMEOUT |
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
253
254
  					WDIOF_KEEPALIVEPING |
  					WDIOF_MAGICCLOSE,
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
255
256
  		.firmware_version =	0,
  		.identity =		ESB_MODULE_NAME,
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
257
258
259
  	};
  
  	switch (cmd) {
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
260
261
262
  	case WDIOC_GETSUPPORT:
  		return copy_to_user(argp, &ident,
  					sizeof(ident)) ? -EFAULT : 0;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
263

0829291ea   Alan Cox   [WATCHDOG 13/57] ...
264
  	case WDIOC_GETSTATUS:
31838d9da   Wim Van Sebroeck   [WATCHDOG] i6300e...
265
  		return put_user(0, p);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
266

0829291ea   Alan Cox   [WATCHDOG 13/57] ...
267
268
  	case WDIOC_GETBOOTSTATUS:
  		return put_user(triggered, p);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
269

0829291ea   Alan Cox   [WATCHDOG 13/57] ...
270
271
272
273
  	case WDIOC_SETOPTIONS:
  	{
  		if (get_user(new_options, p))
  			return -EFAULT;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
274

0829291ea   Alan Cox   [WATCHDOG 13/57] ...
275
276
277
278
  		if (new_options & WDIOS_DISABLECARD) {
  			esb_timer_stop();
  			retval = 0;
  		}
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
279

0829291ea   Alan Cox   [WATCHDOG 13/57] ...
280
  		if (new_options & WDIOS_ENABLECARD) {
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
281
282
283
284
285
  			esb_timer_start();
  			retval = 0;
  		}
  		return retval;
  	}
0c06090c9   Wim Van Sebroeck   [WATCHDOG] Coding...
286
287
288
  	case WDIOC_KEEPALIVE:
  		esb_timer_keepalive();
  		return 0;
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  	case WDIOC_SETTIMEOUT:
  	{
  		if (get_user(new_heartbeat, p))
  			return -EFAULT;
  		if (esb_timer_set_heartbeat(new_heartbeat))
  			return -EINVAL;
  		esb_timer_keepalive();
  		/* Fall */
  	}
  	case WDIOC_GETTIMEOUT:
  		return put_user(heartbeat, p);
  	default:
  		return -ENOTTY;
  	}
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
303
304
305
  }
  
  /*
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
306
307
   *      Kernel Interfaces
   */
62322d255   Arjan van de Ven   [PATCH] make more...
308
  static const struct file_operations esb_fops = {
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
309
310
311
312
313
314
  	.owner = THIS_MODULE,
  	.llseek = no_llseek,
  	.write = esb_write,
  	.unlocked_ioctl = esb_ioctl,
  	.open = esb_open,
  	.release = esb_release,
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
315
316
317
  };
  
  static struct miscdevice esb_miscdev = {
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
318
319
320
  	.minor = WATCHDOG_MINOR,
  	.name = "watchdog",
  	.fops = &esb_fops,
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
321
  };
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
322
323
  /*
   * Data for PCI driver interface
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
324
   */
4562f5394   Wim Van Sebroeck   watchdog: convert...
325
  static DEFINE_PCI_DEVICE_TABLE(esb_pci_tbl) = {
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
326
327
  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
  	{ 0, },                 /* End of list */
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
328
  };
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
329
  MODULE_DEVICE_TABLE(pci, esb_pci_tbl);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
330
331
332
333
  
  /*
   *      Init & exit routines
   */
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
334
  static unsigned char __devinit esb_getdevice(struct pci_dev *pdev)
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
335
  {
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
336
  	if (pci_enable_device(pdev)) {
fc8a9d830   Wim Van Sebroeck   [WATCHDOG] i6300e...
337
338
339
340
  		printk(KERN_ERR PFX "failed to enable device
  ");
  		goto err_devput;
  	}
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
341

2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
342
  	if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) {
fc8a9d830   Wim Van Sebroeck   [WATCHDOG] i6300e...
343
344
345
346
  		printk(KERN_ERR PFX "failed to request region
  ");
  		goto err_disable;
  	}
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
347

2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
348
  	BASEADDR = pci_ioremap_bar(pdev, 0);
fc8a9d830   Wim Van Sebroeck   [WATCHDOG] i6300e...
349
350
351
352
353
354
355
356
  	if (BASEADDR == NULL) {
  		/* Something's wrong here, BASEADDR has to be set */
  		printk(KERN_ERR PFX "failed to get BASEADDR
  ");
  		goto err_release;
  	}
  
  	/* Done */
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
357
  	esb_pci = pdev;
fc8a9d830   Wim Van Sebroeck   [WATCHDOG] i6300e...
358
  	return 1;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
359
360
  
  err_release:
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
361
  	pci_release_region(pdev, 0);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
362
  err_disable:
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
363
  	pci_disable_device(pdev);
811f99916   Naveen Gupta   [WATCHDOG] i6300e...
364
  err_devput:
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
365
366
  	return 0;
  }
fc8a9d830   Wim Van Sebroeck   [WATCHDOG] i6300e...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  static void __devinit esb_initdevice(void)
  {
  	u8 val1;
  	u16 val2;
  
  	/*
  	 * Config register:
  	 * Bit    5 : 0 = Enable WDT_OUTPUT
  	 * Bit    2 : 0 = set the timer frequency to the PCI clock
  	 * divided by 2^15 (approx 1KHz).
  	 * Bits 1:0 : 11 = WDT_INT_TYPE Disabled.
  	 * The watchdog has two timers, it can be setup so that the
  	 * expiry of timer1 results in an interrupt and the expiry of
  	 * timer2 results in a reboot. We set it to not generate
  	 * any interrupts as there is not much we can do with it
  	 * right now.
  	 */
  	pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003);
  
  	/* Check that the WDT isn't already locked */
  	pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
  	if (val1 & ESB_WDT_LOCK)
  		printk(KERN_WARNING PFX "nowayout already set
  ");
  
  	/* Set the timer to watchdog mode and disable it for now */
  	pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
  
  	/* Check if the watchdog was previously triggered */
  	esb_unlock_registers();
  	val2 = readw(ESB_RELOAD_REG);
  	if (val2 & ESB_WDT_TIMEOUT)
  		triggered = WDIOF_CARDRESET;
  
  	/* Reset WDT_TIMEOUT flag and timers */
  	esb_unlock_registers();
  	writew((ESB_WDT_TIMEOUT | ESB_WDT_RELOAD), ESB_RELOAD_REG);
  
  	/* And set the correct timeout value */
  	esb_timer_set_heartbeat(heartbeat);
  }
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
408
409
  static int __devinit esb_probe(struct pci_dev *pdev,
  		const struct pci_device_id *ent)
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
410
  {
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
411
  	int ret;
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
412
413
414
415
416
417
418
419
420
421
422
  	cards_found++;
  	if (cards_found == 1)
  		printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s
  ",
  			ESB_VERSION);
  
  	if (cards_found > 1) {
  		printk(KERN_ERR PFX "This driver only supports 1 device
  ");
  		return -ENODEV;
  	}
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
423
  	/* Check whether or not the hardware watchdog is there */
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
424
  	if (!esb_getdevice(pdev) || esb_pci == NULL)
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
425
426
427
428
  		return -ENODEV;
  
  	/* Check that the heartbeat value is within it's range;
  	   if not reset to the default */
fc8a9d830   Wim Van Sebroeck   [WATCHDOG] i6300e...
429
430
  	if (heartbeat < 0x1 || heartbeat > 2 * 0x03ff) {
  		heartbeat = WATCHDOG_HEARTBEAT;
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
431
432
433
434
435
  		printk(KERN_INFO PFX
  			"heartbeat value must be 1<heartbeat<2046, using %d
  ",
  								heartbeat);
  	}
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
436

fc8a9d830   Wim Van Sebroeck   [WATCHDOG] i6300e...
437
438
439
440
  	/* Initialize the watchdog and make sure it does not run */
  	esb_initdevice();
  
  	/* Register the watchdog so that userspace has access to it */
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
441
442
443
444
445
446
  	ret = misc_register(&esb_miscdev);
  	if (ret != 0) {
  		printk(KERN_ERR PFX
  			"cannot register miscdev on minor=%d (err=%d)
  ",
  							WATCHDOG_MINOR, ret);
0426fd0d8   Wim Van Sebroeck   [WATCHDOG] i6300e...
447
  		goto err_unmap;
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
448
  	}
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
449
450
451
452
453
  	printk(KERN_INFO PFX
  		"initialized (0x%p). heartbeat=%d sec (nowayout=%d)
  ",
  						BASEADDR, heartbeat, nowayout);
  	return 0;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
454

cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
455
456
  err_unmap:
  	iounmap(BASEADDR);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
457
  	pci_release_region(esb_pci, 0);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
458
  	pci_disable_device(esb_pci);
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
459
  	esb_pci = NULL;
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
460
  	return ret;
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
461
  }
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
462
  static void __devexit esb_remove(struct pci_dev *pdev)
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
463
464
465
  {
  	/* Stop the timer before we leave */
  	if (!nowayout)
0829291ea   Alan Cox   [WATCHDOG 13/57] ...
466
  		esb_timer_stop();
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
467
468
469
  
  	/* Deregister */
  	misc_deregister(&esb_miscdev);
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
470
471
472
  	iounmap(BASEADDR);
  	pci_release_region(esb_pci, 0);
  	pci_disable_device(esb_pci);
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
473
  	esb_pci = NULL;
0426fd0d8   Wim Van Sebroeck   [WATCHDOG] i6300e...
474
  }
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
475
  static void esb_shutdown(struct pci_dev *pdev)
0426fd0d8   Wim Van Sebroeck   [WATCHDOG] i6300e...
476
477
478
  {
  	esb_timer_stop();
  }
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
479
480
481
  static struct pci_driver esb_driver = {
  	.name		= ESB_MODULE_NAME,
  	.id_table	= esb_pci_tbl,
0426fd0d8   Wim Van Sebroeck   [WATCHDOG] i6300e...
482
483
484
  	.probe          = esb_probe,
  	.remove         = __devexit_p(esb_remove),
  	.shutdown       = esb_shutdown,
0426fd0d8   Wim Van Sebroeck   [WATCHDOG] i6300e...
485
486
487
488
  };
  
  static int __init watchdog_init(void)
  {
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
489
  	return pci_register_driver(&esb_driver);
0426fd0d8   Wim Van Sebroeck   [WATCHDOG] i6300e...
490
491
492
493
  }
  
  static void __exit watchdog_cleanup(void)
  {
2786095a5   Wim Van Sebroeck   [WATCHDOG] i6300e...
494
  	pci_unregister_driver(&esb_driver);
0426fd0d8   Wim Van Sebroeck   [WATCHDOG] i6300e...
495
496
  	printk(KERN_INFO PFX "Watchdog Module Unloaded.
  ");
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
497
498
499
500
  }
  
  module_init(watchdog_init);
  module_exit(watchdog_cleanup);
96de0e252   Jan Engelhardt   Convert files to ...
501
  MODULE_AUTHOR("Ross Biro and David Härdeman");
cc90ef0f9   David Hardeman   [WATCHDOG] i6300e...
502
503
504
  MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);