Linux Audio

Check our new training course

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