1/*
2 *      Intel_SCU 0.2:  An Intel SCU IOH Based Watchdog Device
3 *			for Intel part #(s):
4 *				- AF82MP20 PCH
5 *
6 *      Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
7 *
8 *      This program is free software; you can redistribute it and/or
9 *      modify it under the terms of version 2 of the GNU General
10 *      Public License as published by the Free Software Foundation.
11 *
12 *      This program is distributed in the hope that it will be
13 *      useful, but WITHOUT ANY WARRANTY; without even the implied
14 *      warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 *      PURPOSE.  See the GNU General Public License for more details.
16 *      You should have received a copy of the GNU General Public
17 *      License along with this program; if not, write to the Free
18 *      Software Foundation, Inc., 59 Temple Place - Suite 330,
19 *      Boston, MA  02111-1307, USA.
20 *      The full GNU General Public License is included in this
21 *      distribution in the file called COPYING.
22 *
23 */
24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#include <linux/compiler.h>
28#include <linux/module.h>
29#include <linux/kernel.h>
30#include <linux/moduleparam.h>
31#include <linux/types.h>
32#include <linux/miscdevice.h>
33#include <linux/watchdog.h>
34#include <linux/fs.h>
35#include <linux/notifier.h>
36#include <linux/reboot.h>
37#include <linux/init.h>
38#include <linux/jiffies.h>
39#include <linux/uaccess.h>
40#include <linux/slab.h>
41#include <linux/io.h>
42#include <linux/interrupt.h>
43#include <linux/delay.h>
44#include <linux/sched.h>
45#include <linux/signal.h>
46#include <linux/sfi.h>
47#include <asm/irq.h>
48#include <linux/atomic.h>
49#include <asm/intel_scu_ipc.h>
50#include <asm/apb_timer.h>
51#include <asm/intel-mid.h>
52
53#include "intel_scu_watchdog.h"
54
55/* Bounds number of times we will retry loading time count */
56/* This retry is a work around for a silicon bug.	   */
57#define MAX_RETRY 16
58
59#define IPC_SET_WATCHDOG_TIMER	0xF8
60
61static int timer_margin = DEFAULT_SOFT_TO_HARD_MARGIN;
62module_param(timer_margin, int, 0);
63MODULE_PARM_DESC(timer_margin,
64		"Watchdog timer margin"
65		"Time between interrupt and resetting the system"
66		"The range is from 1 to 160"
67		"This is the time for all keep alives to arrive");
68
69static int timer_set = DEFAULT_TIME;
70module_param(timer_set, int, 0);
71MODULE_PARM_DESC(timer_set,
72		"Default Watchdog timer setting"
73		"Complete cycle time"
74		"The range is from 1 to 170"
75		"This is the time for all keep alives to arrive");
76
77/* After watchdog device is closed, check force_boot. If:
78 * force_boot == 0, then force boot on next watchdog interrupt after close,
79 * force_boot == 1, then force boot immediately when device is closed.
80 */
81static int force_boot;
82module_param(force_boot, int, 0);
83MODULE_PARM_DESC(force_boot,
84		"A value of 1 means that the driver will reboot"
85		"the system immediately if the /dev/watchdog device is closed"
86		"A value of 0 means that when /dev/watchdog device is closed"
87		"the watchdog timer will be refreshed for one more interval"
88		"of length: timer_set. At the end of this interval, the"
89		"watchdog timer will reset the system."
90		);
91
92/* there is only one device in the system now; this can be made into
93 * an array in the future if we have more than one device */
94
95static struct intel_scu_watchdog_dev watchdog_device;
96
97/* Forces restart, if force_reboot is set */
98static void watchdog_fire(void)
99{
100	if (force_boot) {
101		pr_crit("Initiating system reboot\n");
102		emergency_restart();
103		pr_crit("Reboot didn't ?????\n");
104	}
105
106	else {
107		pr_crit("Immediate Reboot Disabled\n");
108		pr_crit("System will reset when watchdog timer times out!\n");
109	}
110}
111
112static int check_timer_margin(int new_margin)
113{
114	if ((new_margin < MIN_TIME_CYCLE) ||
115	    (new_margin > MAX_TIME - timer_set)) {
116		pr_debug("value of new_margin %d is out of the range %d to %d\n",
117			 new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
118		return -EINVAL;
119	}
120	return 0;
121}
122
123/*
124 * IPC operations
125 */
126static int watchdog_set_ipc(int soft_threshold, int threshold)
127{
128	u32	*ipc_wbuf;
129	u8	 cbuf[16] = { '\0' };
130	int	 ipc_ret = 0;
131
132	ipc_wbuf = (u32 *)&cbuf;
133	ipc_wbuf[0] = soft_threshold;
134	ipc_wbuf[1] = threshold;
135
136	ipc_ret = intel_scu_ipc_command(
137			IPC_SET_WATCHDOG_TIMER,
138			0,
139			ipc_wbuf,
140			2,
141			NULL,
142			0);
143
144	if (ipc_ret != 0)
145		pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret);
146
147	return ipc_ret;
148};
149
150/*
151 *      Intel_SCU operations
152 */
153
154/* timer interrupt handler */
155static irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
156{
157	int int_status;
158	int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
159
160	pr_debug("irq, int_status: %x\n", int_status);
161
162	if (int_status != 0)
163		return IRQ_NONE;
164
165	/* has the timer been started? If not, then this is spurious */
166	if (watchdog_device.timer_started == 0) {
167		pr_debug("spurious interrupt received\n");
168		return IRQ_HANDLED;
169	}
170
171	/* temporarily disable the timer */
172	iowrite32(0x00000002, watchdog_device.timer_control_addr);
173
174	/* set the timer to the threshold */
175	iowrite32(watchdog_device.threshold,
176		  watchdog_device.timer_load_count_addr);
177
178	/* allow the timer to run */
179	iowrite32(0x00000003, watchdog_device.timer_control_addr);
180
181	return IRQ_HANDLED;
182}
183
184static int intel_scu_keepalive(void)
185{
186
187	/* read eoi register - clears interrupt */
188	ioread32(watchdog_device.timer_clear_interrupt_addr);
189
190	/* temporarily disable the timer */
191	iowrite32(0x00000002, watchdog_device.timer_control_addr);
192
193	/* set the timer to the soft_threshold */
194	iowrite32(watchdog_device.soft_threshold,
195		  watchdog_device.timer_load_count_addr);
196
197	/* allow the timer to run */
198	iowrite32(0x00000003, watchdog_device.timer_control_addr);
199
200	return 0;
201}
202
203static int intel_scu_stop(void)
204{
205	iowrite32(0, watchdog_device.timer_control_addr);
206	return 0;
207}
208
209static int intel_scu_set_heartbeat(u32 t)
210{
211	int			 ipc_ret;
212	int			 retry_count;
213	u32			 soft_value;
214	u32			 hw_value;
215
216	watchdog_device.timer_set = t;
217	watchdog_device.threshold =
218		timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
219	watchdog_device.soft_threshold =
220		(watchdog_device.timer_set - timer_margin)
221		* watchdog_device.timer_tbl_ptr->freq_hz;
222
223	pr_debug("set_heartbeat: timer freq is %d\n",
224		 watchdog_device.timer_tbl_ptr->freq_hz);
225	pr_debug("set_heartbeat: timer_set is %x (hex)\n",
226		 watchdog_device.timer_set);
227	pr_debug("set_hearbeat: timer_margin is %x (hex)\n", timer_margin);
228	pr_debug("set_heartbeat: threshold is %x (hex)\n",
229		 watchdog_device.threshold);
230	pr_debug("set_heartbeat: soft_threshold is %x (hex)\n",
231		 watchdog_device.soft_threshold);
232
233	/* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */
234	/* watchdog timing come out right. */
235	watchdog_device.threshold =
236		watchdog_device.threshold / FREQ_ADJUSTMENT;
237	watchdog_device.soft_threshold =
238		watchdog_device.soft_threshold / FREQ_ADJUSTMENT;
239
240	/* temporarily disable the timer */
241	iowrite32(0x00000002, watchdog_device.timer_control_addr);
242
243	/* send the threshold and soft_threshold via IPC to the processor */
244	ipc_ret = watchdog_set_ipc(watchdog_device.soft_threshold,
245				   watchdog_device.threshold);
246
247	if (ipc_ret != 0) {
248		/* Make sure the watchdog timer is stopped */
249		intel_scu_stop();
250		return ipc_ret;
251	}
252
253	/* Soft Threshold set loop. Early versions of silicon did */
254	/* not always set this count correctly.  This loop checks */
255	/* the value and retries if it was not set correctly.     */
256
257	retry_count = 0;
258	soft_value = watchdog_device.soft_threshold & 0xFFFF0000;
259	do {
260
261		/* Make sure timer is stopped */
262		intel_scu_stop();
263
264		if (MAX_RETRY < retry_count++) {
265			/* Unable to set timer value */
266			pr_err("Unable to set timer\n");
267			return -ENODEV;
268		}
269
270		/* set the timer to the soft threshold */
271		iowrite32(watchdog_device.soft_threshold,
272			watchdog_device.timer_load_count_addr);
273
274		/* read count value before starting timer */
275		ioread32(watchdog_device.timer_load_count_addr);
276
277		/* Start the timer */
278		iowrite32(0x00000003, watchdog_device.timer_control_addr);
279
280		/* read the value the time loaded into its count reg */
281		hw_value = ioread32(watchdog_device.timer_load_count_addr);
282		hw_value = hw_value & 0xFFFF0000;
283
284
285	} while (soft_value != hw_value);
286
287	watchdog_device.timer_started = 1;
288
289	return 0;
290}
291
292/*
293 * /dev/watchdog handling
294 */
295
296static int intel_scu_open(struct inode *inode, struct file *file)
297{
298
299	/* Set flag to indicate that watchdog device is open */
300	if (test_and_set_bit(0, &watchdog_device.driver_open))
301		return -EBUSY;
302
303	/* Check for reopen of driver. Reopens are not allowed */
304	if (watchdog_device.driver_closed)
305		return -EPERM;
306
307	return nonseekable_open(inode, file);
308}
309
310static int intel_scu_release(struct inode *inode, struct file *file)
311{
312	/*
313	 * This watchdog should not be closed, after the timer
314	 * is started with the WDIPC_SETTIMEOUT ioctl
315	 * If force_boot is set watchdog_fire() will cause an
316	 * immediate reset. If force_boot is not set, the watchdog
317	 * timer is refreshed for one more interval. At the end
318	 * of that interval, the watchdog timer will reset the system.
319	 */
320
321	if (!test_and_clear_bit(0, &watchdog_device.driver_open)) {
322		pr_debug("intel_scu_release, without open\n");
323		return -ENOTTY;
324	}
325
326	if (!watchdog_device.timer_started) {
327		/* Just close, since timer has not been started */
328		pr_debug("closed, without starting timer\n");
329		return 0;
330	}
331
332	pr_crit("Unexpected close of /dev/watchdog!\n");
333
334	/* Since the timer was started, prevent future reopens */
335	watchdog_device.driver_closed = 1;
336
337	/* Refresh the timer for one more interval */
338	intel_scu_keepalive();
339
340	/* Reboot system (if force_boot is set) */
341	watchdog_fire();
342
343	/* We should only reach this point if force_boot is not set */
344	return 0;
345}
346
347static ssize_t intel_scu_write(struct file *file,
348			      char const *data,
349			      size_t len,
350			      loff_t *ppos)
351{
352
353	if (watchdog_device.timer_started)
354		/* Watchdog already started, keep it alive */
355		intel_scu_keepalive();
356	else
357		/* Start watchdog with timer value set by init */
358		intel_scu_set_heartbeat(watchdog_device.timer_set);
359
360	return len;
361}
362
363static long intel_scu_ioctl(struct file *file,
364			   unsigned int cmd,
365			   unsigned long arg)
366{
367	void __user *argp = (void __user *)arg;
368	u32 __user *p = argp;
369	u32 new_margin;
370
371
372	static const struct watchdog_info ident = {
373		.options =          WDIOF_SETTIMEOUT
374				    | WDIOF_KEEPALIVEPING,
375		.firmware_version = 0,  /* @todo Get from SCU via
376						 ipc_get_scu_fw_version()? */
377		.identity =         "Intel_SCU IOH Watchdog"  /* len < 32 */
378	};
379
380	switch (cmd) {
381	case WDIOC_GETSUPPORT:
382		return copy_to_user(argp,
383				    &ident,
384				    sizeof(ident)) ? -EFAULT : 0;
385	case WDIOC_GETSTATUS:
386	case WDIOC_GETBOOTSTATUS:
387		return put_user(0, p);
388	case WDIOC_KEEPALIVE:
389		intel_scu_keepalive();
390
391		return 0;
392	case WDIOC_SETTIMEOUT:
393		if (get_user(new_margin, p))
394			return -EFAULT;
395
396		if (check_timer_margin(new_margin))
397			return -EINVAL;
398
399		if (intel_scu_set_heartbeat(new_margin))
400			return -EINVAL;
401		return 0;
402	case WDIOC_GETTIMEOUT:
403		return put_user(watchdog_device.soft_threshold, p);
404
405	default:
406		return -ENOTTY;
407	}
408}
409
410/*
411 *      Notifier for system down
412 */
413static int intel_scu_notify_sys(struct notifier_block *this,
414			       unsigned long code,
415			       void *another_unused)
416{
417	if (code == SYS_DOWN || code == SYS_HALT)
418		/* Turn off the watchdog timer. */
419		intel_scu_stop();
420	return NOTIFY_DONE;
421}
422
423/*
424 *      Kernel Interfaces
425 */
426static const struct file_operations intel_scu_fops = {
427	.owner          = THIS_MODULE,
428	.llseek         = no_llseek,
429	.write          = intel_scu_write,
430	.unlocked_ioctl = intel_scu_ioctl,
431	.open           = intel_scu_open,
432	.release        = intel_scu_release,
433};
434
435static int __init intel_scu_watchdog_init(void)
436{
437	int ret;
438	u32 __iomem *tmp_addr;
439
440	/*
441	 * We don't really need to check this as the SFI timer get will fail
442	 * but if we do so we can exit with a clearer reason and no noise.
443	 *
444	 * If it isn't an intel MID device then it doesn't have this watchdog
445	 */
446	if (!intel_mid_identify_cpu())
447		return -ENODEV;
448
449	/* Check boot parameters to verify that their initial values */
450	/* are in range. */
451	/* Check value of timer_set boot parameter */
452	if ((timer_set < MIN_TIME_CYCLE) ||
453	    (timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
454		pr_err("value of timer_set %x (hex) is out of range from %x to %x (hex)\n",
455		       timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
456		return -EINVAL;
457	}
458
459	/* Check value of timer_margin boot parameter */
460	if (check_timer_margin(timer_margin))
461		return -EINVAL;
462
463	watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
464
465	if (watchdog_device.timer_tbl_ptr == NULL) {
466		pr_debug("timer is not available\n");
467		return -ENODEV;
468	}
469	/* make sure the timer exists */
470	if (watchdog_device.timer_tbl_ptr->phys_addr == 0) {
471		pr_debug("timer %d does not have valid physical memory\n",
472			 sfi_mtimer_num);
473		return -ENODEV;
474	}
475
476	if (watchdog_device.timer_tbl_ptr->irq == 0) {
477		pr_debug("timer %d invalid irq\n", sfi_mtimer_num);
478		return -ENODEV;
479	}
480
481	tmp_addr = ioremap_nocache(watchdog_device.timer_tbl_ptr->phys_addr,
482			20);
483
484	if (tmp_addr == NULL) {
485		pr_debug("timer unable to ioremap\n");
486		return -ENOMEM;
487	}
488
489	watchdog_device.timer_load_count_addr = tmp_addr++;
490	watchdog_device.timer_current_value_addr = tmp_addr++;
491	watchdog_device.timer_control_addr = tmp_addr++;
492	watchdog_device.timer_clear_interrupt_addr = tmp_addr++;
493	watchdog_device.timer_interrupt_status_addr = tmp_addr++;
494
495	/* Set the default time values in device structure */
496
497	watchdog_device.timer_set = timer_set;
498	watchdog_device.threshold =
499		timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
500	watchdog_device.soft_threshold =
501		(watchdog_device.timer_set - timer_margin)
502		* watchdog_device.timer_tbl_ptr->freq_hz;
503
504
505	watchdog_device.intel_scu_notifier.notifier_call =
506		intel_scu_notify_sys;
507
508	ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier);
509	if (ret) {
510		pr_err("cannot register notifier %d)\n", ret);
511		goto register_reboot_error;
512	}
513
514	watchdog_device.miscdev.minor = WATCHDOG_MINOR;
515	watchdog_device.miscdev.name = "watchdog";
516	watchdog_device.miscdev.fops = &intel_scu_fops;
517
518	ret = misc_register(&watchdog_device.miscdev);
519	if (ret) {
520		pr_err("cannot register miscdev %d err =%d\n",
521		       WATCHDOG_MINOR, ret);
522		goto misc_register_error;
523	}
524
525	ret = request_irq((unsigned int)watchdog_device.timer_tbl_ptr->irq,
526		watchdog_timer_interrupt,
527		IRQF_SHARED, "watchdog",
528		&watchdog_device.timer_load_count_addr);
529	if (ret) {
530		pr_err("error requesting irq %d\n", ret);
531		goto request_irq_error;
532	}
533	/* Make sure timer is disabled before returning */
534	intel_scu_stop();
535	return 0;
536
537/* error cleanup */
538
539request_irq_error:
540	misc_deregister(&watchdog_device.miscdev);
541misc_register_error:
542	unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
543register_reboot_error:
544	intel_scu_stop();
545	iounmap(watchdog_device.timer_load_count_addr);
546	return ret;
547}
548
549static void __exit intel_scu_watchdog_exit(void)
550{
551
552	misc_deregister(&watchdog_device.miscdev);
553	unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
554	/* disable the timer */
555	iowrite32(0x00000002, watchdog_device.timer_control_addr);
556	iounmap(watchdog_device.timer_load_count_addr);
557}
558
559late_initcall(intel_scu_watchdog_init);
560module_exit(intel_scu_watchdog_exit);
561
562MODULE_AUTHOR("Intel Corporation");
563MODULE_DESCRIPTION("Intel SCU Watchdog Device Driver");
564MODULE_LICENSE("GPL");
565MODULE_VERSION(WDT_VER);
566