Blame view

drivers/watchdog/wdrtas.c 16.6 KB
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  /*
   * FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as
   * RTAS calls are available
   */
  
  /*
   * RTAS watchdog driver
   *
   * (C) Copyright IBM Corp. 2005
   * device driver to exploit watchdog RTAS functions
   *
   * Authors : Utz Bacher <utz.bacher@de.ibm.com>
   *
   * 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, or (at your option)
   * any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
28
29
30
31
32
33
34
35
36
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/miscdevice.h>
  #include <linux/module.h>
  #include <linux/notifier.h>
  #include <linux/reboot.h>
  #include <linux/types.h>
  #include <linux/watchdog.h>
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
37
  #include <linux/uaccess.h>
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
38
39
  
  #include <asm/rtas.h>
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
40
41
42
43
44
45
46
47
48
49
  
  #define WDRTAS_MAGIC_CHAR		42
  #define WDRTAS_SUPPORTED_MASK		(WDIOF_SETTIMEOUT | \
  					 WDIOF_MAGICCLOSE)
  
  MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
  MODULE_DESCRIPTION("RTAS watchdog driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
  MODULE_ALIAS_MISCDEV(TEMP_MINOR);
a77dba7e4   Wim Van Sebroeck   [WATCHDOG] Some m...
50
  static int wdrtas_nowayout = WATCHDOG_NOWAYOUT;
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
51
  static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
52
  static char wdrtas_expect_close;
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  
  static int wdrtas_interval;
  
  #define WDRTAS_THERMAL_SENSOR		3
  static int wdrtas_token_get_sensor_state;
  #define WDRTAS_SURVEILLANCE_IND		9000
  static int wdrtas_token_set_indicator;
  #define WDRTAS_SP_SPI			28
  static int wdrtas_token_get_sp;
  static int wdrtas_token_event_scan;
  
  #define WDRTAS_DEFAULT_INTERVAL		300
  
  #define WDRTAS_LOGBUFFER_LEN		128
  static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN];
  
  
  /*** watchdog access functions */
  
  /**
   * wdrtas_set_interval - sets the watchdog interval
   * @interval: new interval
   *
   * returns 0 on success, <0 on failures
   *
   * wdrtas_set_interval sets the watchdog keepalive interval by calling the
   * RTAS function set-indicator (surveillance). The unit of interval is
   * seconds.
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
82
83
  
  static int wdrtas_set_interval(int interval)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
84
85
86
87
88
89
90
91
92
  {
  	long result;
  	static int print_msg = 10;
  
  	/* rtas uses minutes */
  	interval = (interval + 59) / 60;
  
  	result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
  			   WDRTAS_SURVEILLANCE_IND, 0, interval);
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
93
  	if (result < 0 && print_msg) {
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
94
95
96
97
98
99
100
101
  		printk(KERN_ERR "wdrtas: setting the watchdog to %i "
  		       "timeout failed: %li
  ", interval, result);
  		print_msg--;
  	}
  
  	return result;
  }
b6966b1be   Mark Nelson   powerpc/wdrtas: U...
102
  #define WDRTAS_SP_SPI_LEN 4
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
103
104
105
106
107
108
109
110
111
112
  /**
   * wdrtas_get_interval - returns the current watchdog interval
   * @fallback_value: value (in seconds) to use, if the RTAS call fails
   *
   * returns the interval
   *
   * wdrtas_get_interval returns the current watchdog keepalive interval
   * as reported by the RTAS function ibm,get-system-parameter. The unit
   * of the return value is seconds.
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
113
  static int wdrtas_get_interval(int fallback_value)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
114
115
  {
  	long result;
b6966b1be   Mark Nelson   powerpc/wdrtas: U...
116
  	char value[WDRTAS_SP_SPI_LEN];
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
117

b6966b1be   Mark Nelson   powerpc/wdrtas: U...
118
119
  	spin_lock(&rtas_data_buf_lock);
  	memset(rtas_data_buf, 0, WDRTAS_SP_SPI_LEN);
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
120
  	result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL,
b6966b1be   Mark Nelson   powerpc/wdrtas: U...
121
122
123
124
125
  			   WDRTAS_SP_SPI, __pa(rtas_data_buf),
  			   WDRTAS_SP_SPI_LEN);
  
  	memcpy(value, rtas_data_buf, WDRTAS_SP_SPI_LEN);
  	spin_unlock(&rtas_data_buf_lock);
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
126
  	if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) {
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  		printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog "
  		       "timeout (%li). Continuing
  ", result);
  		return fallback_value;
  	}
  
  	/* rtas uses minutes */
  	return ((int)value[2]) * 60;
  }
  
  /**
   * wdrtas_timer_start - starts watchdog
   *
   * wdrtas_timer_start starts the watchdog by calling the RTAS function
   * set-interval (surveillance)
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
143
  static void wdrtas_timer_start(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
144
145
146
147
148
149
150
151
152
153
  {
  	wdrtas_set_interval(wdrtas_interval);
  }
  
  /**
   * wdrtas_timer_stop - stops watchdog
   *
   * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function
   * set-interval (surveillance)
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
154
  static void wdrtas_timer_stop(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
155
156
157
158
159
160
161
162
163
164
  {
  	wdrtas_set_interval(0);
  }
  
  /**
   * wdrtas_log_scanned_event - logs an event we received during keepalive
   *
   * wdrtas_log_scanned_event prints a message to the log buffer dumping
   * the results of the last event-scan call
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
165
  static void wdrtas_log_scanned_event(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
166
167
168
169
170
171
172
173
174
  {
  	int i;
  
  	for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16)
  		printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = "
  		       "%02x %02x %02x %02x  %02x %02x %02x %02x   "
  		       "%02x %02x %02x %02x  %02x %02x %02x %02x
  ",
  		       (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
175
176
177
178
179
180
181
  		       wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
  		       wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
  		       wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
  		       wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
  		       wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
  		       wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
  		       wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
182
183
184
185
186
187
188
189
190
191
  		       wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
  }
  
  /**
   * wdrtas_timer_keepalive - resets watchdog timer to keep system alive
   *
   * wdrtas_timer_keepalive restarts the watchdog timer by calling the
   * RTAS function event-scan and repeats these calls as long as there are
   * events available. All events will be dumped.
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
192
  static void wdrtas_timer_keepalive(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  {
  	long result;
  
  	do {
  		result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL,
  				   RTAS_EVENT_SCAN_ALL_EVENTS, 0,
  				   (void *)__pa(wdrtas_logbuffer),
  				   WDRTAS_LOGBUFFER_LEN);
  		if (result < 0)
  			printk(KERN_ERR "wdrtas: event-scan failed: %li
  ",
  			       result);
  		if (result == 0)
  			wdrtas_log_scanned_event();
  	} while (result == 0);
  }
  
  /**
   * wdrtas_get_temperature - returns current temperature
   *
   * returns temperature or <0 on failures
   *
   * wdrtas_get_temperature returns the current temperature in Fahrenheit. It
   * uses the RTAS call get-sensor-state, token 3 to do so
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
218
  static int wdrtas_get_temperature(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
219
  {
5ba762c9b   Adrian Reber   powerpc/rtas: Fix...
220
  	int result;
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
221
  	int temperature = 0;
5ba762c9b   Adrian Reber   powerpc/rtas: Fix...
222
  	result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
223
224
225
  
  	if (result < 0)
  		printk(KERN_WARNING "wdrtas: reading the thermal sensor "
5ba762c9b   Adrian Reber   powerpc/rtas: Fix...
226
227
  		       "failed: %i
  ", result);
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
228
229
230
231
232
233
234
235
236
237
238
239
  	else
  		temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
  
  	return temperature;
  }
  
  /**
   * wdrtas_get_status - returns the status of the watchdog
   *
   * returns a bitmask of defines WDIOF_... as defined in
   * include/linux/watchdog.h
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
240
  static int wdrtas_get_status(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
241
242
243
244
245
246
247
248
249
250
  {
  	return 0; /* TODO */
  }
  
  /**
   * wdrtas_get_boot_status - returns the reason for the last boot
   *
   * returns a bitmask of defines WDIOF_... as defined in
   * include/linux/watchdog.h, indicating why the watchdog rebooted the system
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
251
  static int wdrtas_get_boot_status(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  {
  	return 0; /* TODO */
  }
  
  /*** watchdog API and operations stuff */
  
  /* wdrtas_write - called when watchdog device is written to
   * @file: file structure
   * @buf: user buffer with data
   * @len: amount to data written
   * @ppos: position in file
   *
   * returns the number of successfully processed characters, which is always
   * the number of bytes passed to this function
   *
   * wdrtas_write processes all the data given to it and looks for the magic
   * character 'V'. This character allows the watchdog device to be closed
   * properly.
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
271
  static ssize_t wdrtas_write(struct file *file, const char __user *buf,
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  	     size_t len, loff_t *ppos)
  {
  	int i;
  	char c;
  
  	if (!len)
  		goto out;
  
  	if (!wdrtas_nowayout) {
  		wdrtas_expect_close = 0;
  		/* look for 'V' */
  		for (i = 0; i < len; i++) {
  			if (get_user(c, buf + i))
  				return -EFAULT;
  			/* allow to close device */
  			if (c == 'V')
  				wdrtas_expect_close = WDRTAS_MAGIC_CHAR;
  		}
  	}
  
  	wdrtas_timer_keepalive();
  
  out:
  	return len;
  }
  
  /**
   * wdrtas_ioctl - ioctl function for the watchdog device
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
300
301
302
303
304
305
306
307
   * @file: file structure
   * @cmd: command for ioctl
   * @arg: argument pointer
   *
   * returns 0 on success, <0 on failure
   *
   * wdrtas_ioctl implements the watchdog API ioctls
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
308
309
310
  
  static long wdrtas_ioctl(struct file *file, unsigned int cmd,
  							unsigned long arg)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
311
  {
e896fd986   Al Viro   [PATCH] wdrtas.c:...
312
  	int __user *argp = (void __user *)arg;
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
313
  	int i;
42747d712   Wim Van Sebroeck   [WATCHDOG] watchd...
314
  	static const struct watchdog_info wdinfo = {
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
315
316
  		.options = WDRTAS_SUPPORTED_MASK,
  		.firmware_version = 0,
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
317
  		.identity = "wdrtas",
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  	};
  
  	switch (cmd) {
  	case WDIOC_GETSUPPORT:
  		if (copy_to_user(argp, &wdinfo, sizeof(wdinfo)))
  			return -EFAULT;
  		return 0;
  
  	case WDIOC_GETSTATUS:
  		i = wdrtas_get_status();
  		return put_user(i, argp);
  
  	case WDIOC_GETBOOTSTATUS:
  		i = wdrtas_get_boot_status();
  		return put_user(i, argp);
  
  	case WDIOC_GETTEMP:
  		if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE)
  			return -EOPNOTSUPP;
  
  		i = wdrtas_get_temperature();
  		return put_user(i, argp);
  
  	case WDIOC_SETOPTIONS:
  		if (get_user(i, argp))
  			return -EFAULT;
  		if (i & WDIOS_DISABLECARD)
  			wdrtas_timer_stop();
  		if (i & WDIOS_ENABLECARD) {
  			wdrtas_timer_keepalive();
  			wdrtas_timer_start();
  		}
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
350
  		/* not implemented. Done by H8
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
351
  		if (i & WDIOS_TEMPPANIC) {
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
352
  		} */
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  		return 0;
  
  	case WDIOC_KEEPALIVE:
  		wdrtas_timer_keepalive();
  		return 0;
  
  	case WDIOC_SETTIMEOUT:
  		if (get_user(i, argp))
  			return -EFAULT;
  
  		if (wdrtas_set_interval(i))
  			return -EINVAL;
  
  		wdrtas_timer_keepalive();
  
  		if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
  			wdrtas_interval = i;
  		else
  			wdrtas_interval = wdrtas_get_interval(i);
  		/* fallthrough */
  
  	case WDIOC_GETTIMEOUT:
  		return put_user(wdrtas_interval, argp);
  
  	default:
795b89d20   Samuel Tardieu   [WATCHDOG] use EN...
378
  		return -ENOTTY;
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
379
380
381
382
383
384
385
386
387
388
389
390
391
  	}
  }
  
  /**
   * wdrtas_open - open function of watchdog device
   * @inode: inode structure
   * @file: file structure
   *
   * returns 0 on success, -EBUSY if the file has been opened already, <0 on
   * other failures
   *
   * function called when watchdog device is opened
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
392
  static int wdrtas_open(struct inode *inode, struct file *file)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
  {
  	/* only open once */
  	if (atomic_inc_return(&wdrtas_miscdev_open) > 1) {
  		atomic_dec(&wdrtas_miscdev_open);
  		return -EBUSY;
  	}
  
  	wdrtas_timer_start();
  	wdrtas_timer_keepalive();
  
  	return nonseekable_open(inode, file);
  }
  
  /**
   * wdrtas_close - close function of watchdog device
   * @inode: inode structure
   * @file: file structure
   *
   * returns 0 on success
   *
   * close function. Always succeeds
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
415
  static int wdrtas_close(struct inode *inode, struct file *file)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  {
  	/* only stop watchdog, if this was announced using 'V' before */
  	if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
  		wdrtas_timer_stop();
  	else {
  		printk(KERN_WARNING "wdrtas: got unexpected close. Watchdog "
  		       "not stopped.
  ");
  		wdrtas_timer_keepalive();
  	}
  
  	wdrtas_expect_close = 0;
  	atomic_dec(&wdrtas_miscdev_open);
  	return 0;
  }
  
  /**
   * wdrtas_temp_read - gives back the temperature in fahrenheit
   * @file: file structure
   * @buf: user buffer
   * @count: number of bytes to be read
   * @ppos: position in file
   *
   * returns always 1 or -EFAULT in case of user space copy failures, <0 on
   * other failures
   *
   * wdrtas_temp_read gives the temperature to the users by copying this
   * value as one byte into the user space buffer. The unit is Fahrenheit...
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
445
  static ssize_t wdrtas_temp_read(struct file *file, char __user *buf,
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
  		 size_t count, loff_t *ppos)
  {
  	int temperature = 0;
  
  	temperature = wdrtas_get_temperature();
  	if (temperature < 0)
  		return temperature;
  
  	if (copy_to_user(buf, &temperature, 1))
  		return -EFAULT;
  
  	return 1;
  }
  
  /**
   * wdrtas_temp_open - open function of temperature device
   * @inode: inode structure
   * @file: file structure
   *
   * returns 0 on success, <0 on failure
   *
   * function called when temperature device is opened
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
469
  static int wdrtas_temp_open(struct inode *inode, struct file *file)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
470
471
472
473
474
475
476
477
478
479
480
481
482
  {
  	return nonseekable_open(inode, file);
  }
  
  /**
   * wdrtas_temp_close - close function of temperature device
   * @inode: inode structure
   * @file: file structure
   *
   * returns 0 on success
   *
   * close function. Always succeeds
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
483
  static int wdrtas_temp_close(struct inode *inode, struct file *file)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  {
  	return 0;
  }
  
  /**
   * wdrtas_reboot - reboot notifier function
   * @nb: notifier block structure
   * @code: reboot code
   * @ptr: unused
   *
   * returns NOTIFY_DONE
   *
   * wdrtas_reboot stops the watchdog in case of a reboot
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
498
499
  static int wdrtas_reboot(struct notifier_block *this,
  					unsigned long code, void *ptr)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
500
  {
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
501
  	if (code == SYS_DOWN || code == SYS_HALT)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
502
503
504
505
506
507
  		wdrtas_timer_stop();
  
  	return NOTIFY_DONE;
  }
  
  /*** initialization stuff */
62322d255   Arjan van de Ven   [PATCH] make more...
508
  static const struct file_operations wdrtas_fops = {
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
509
510
511
  	.owner		= THIS_MODULE,
  	.llseek		= no_llseek,
  	.write		= wdrtas_write,
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
512
  	.unlocked_ioctl	= wdrtas_ioctl,
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
513
514
515
516
517
518
519
520
521
  	.open		= wdrtas_open,
  	.release	= wdrtas_close,
  };
  
  static struct miscdevice wdrtas_miscdev = {
  	.minor =	WATCHDOG_MINOR,
  	.name =		"watchdog",
  	.fops =		&wdrtas_fops,
  };
62322d255   Arjan van de Ven   [PATCH] make more...
522
  static const struct file_operations wdrtas_temp_fops = {
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  	.owner		= THIS_MODULE,
  	.llseek		= no_llseek,
  	.read		= wdrtas_temp_read,
  	.open		= wdrtas_temp_open,
  	.release	= wdrtas_temp_close,
  };
  
  static struct miscdevice wdrtas_tempdev = {
  	.minor =	TEMP_MINOR,
  	.name =		"temperature",
  	.fops =		&wdrtas_temp_fops,
  };
  
  static struct notifier_block wdrtas_notifier = {
  	.notifier_call =	wdrtas_reboot,
  };
  
  /**
   * wdrtas_get_tokens - reads in RTAS tokens
   *
af901ca18   André Goddard Rosa   tree-wide: fix as...
543
   * returns 0 on success, <0 on failure
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
544
545
546
547
548
   *
   * wdrtas_get_tokens reads in the tokens for the RTAS calls used in
   * this watchdog driver. It tolerates, if "get-sensor-state" and
   * "ibm,get-system-parameter" are not available.
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
549
  static int wdrtas_get_tokens(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  {
  	wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
  	if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
  		printk(KERN_WARNING "wdrtas: couldn't get token for "
  		       "get-sensor-state. Trying to continue without "
  		       "temperature support.
  ");
  	}
  
  	wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
  	if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
  		printk(KERN_WARNING "wdrtas: couldn't get token for "
  		       "ibm,get-system-parameter. Trying to continue with "
  		       "a default timeout value of %i seconds.
  ",
  		       WDRTAS_DEFAULT_INTERVAL);
  	}
  
  	wdrtas_token_set_indicator = rtas_token("set-indicator");
  	if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
  		printk(KERN_ERR "wdrtas: couldn't get token for "
  		       "set-indicator. Terminating watchdog code.
  ");
  		return -EIO;
  	}
  
  	wdrtas_token_event_scan = rtas_token("event-scan");
  	if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
  		printk(KERN_ERR "wdrtas: couldn't get token for event-scan. "
  		       "Terminating watchdog code.
  ");
  		return -EIO;
  	}
  
  	return 0;
  }
  
  /**
   * wdrtas_unregister_devs - unregisters the misc dev handlers
   *
   * wdrtas_register_devs unregisters the watchdog and temperature watchdog
   * misc devs
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
593
  static void wdrtas_unregister_devs(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
594
595
596
597
598
599
600
601
602
  {
  	misc_deregister(&wdrtas_miscdev);
  	if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE)
  		misc_deregister(&wdrtas_tempdev);
  }
  
  /**
   * wdrtas_register_devs - registers the misc dev handlers
   *
af901ca18   André Goddard Rosa   tree-wide: fix as...
603
   * returns 0 on success, <0 on failure
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
604
605
606
607
   *
   * wdrtas_register_devs registers the watchdog and temperature watchdog
   * misc devs
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
608
  static int wdrtas_register_devs(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  {
  	int result;
  
  	result = misc_register(&wdrtas_miscdev);
  	if (result) {
  		printk(KERN_ERR "wdrtas: couldn't register watchdog misc "
  		       "device. Terminating watchdog code.
  ");
  		return result;
  	}
  
  	if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
  		result = misc_register(&wdrtas_tempdev);
  		if (result) {
  			printk(KERN_WARNING "wdrtas: couldn't register "
  			       "watchdog temperature misc device. Continuing "
  			       "without temperature support.
  ");
  			wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
  		}
  	}
  
  	return 0;
  }
  
  /**
   * wdrtas_init - init function of the watchdog driver
   *
af901ca18   André Goddard Rosa   tree-wide: fix as...
637
   * returns 0 on success, <0 on failure
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
638
639
640
   *
   * registers the file handlers and the reboot notifier
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
641
  static int __init wdrtas_init(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
  {
  	if (wdrtas_get_tokens())
  		return -ENODEV;
  
  	if (wdrtas_register_devs())
  		return -ENODEV;
  
  	if (register_reboot_notifier(&wdrtas_notifier)) {
  		printk(KERN_ERR "wdrtas: could not register reboot notifier. "
  		       "Terminating watchdog code.
  ");
  		wdrtas_unregister_devs();
  		return -ENODEV;
  	}
  
  	if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
  		wdrtas_interval = WDRTAS_DEFAULT_INTERVAL;
  	else
  		wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL);
  
  	return 0;
  }
  
  /**
   * wdrtas_exit - exit function of the watchdog driver
   *
   * unregisters the file handlers and the reboot notifier
   */
dae67a283   Alan Cox   [WATCHDOG 54/57] ...
670
  static void __exit wdrtas_exit(void)
031f7edec   Utz Bacher   [PATCH] ppc64: ad...
671
672
673
674
675
676
677
678
679
680
681
  {
  	if (!wdrtas_nowayout)
  		wdrtas_timer_stop();
  
  	wdrtas_unregister_devs();
  
  	unregister_reboot_notifier(&wdrtas_notifier);
  }
  
  module_init(wdrtas_init);
  module_exit(wdrtas_exit);