changeset 2036:6b118cfdcfda onnv_41

FWARC 2005/367 sun4v watchdog service API FWARC 2006/093 sun4v watchdog API update 6354584 Add watchdog timer support in sun4v
author wentaoy
date Mon, 22 May 2006 18:36:17 -0700
parents a29bc457bcb9
children 132880d31aba
files usr/src/uts/common/os/clock.c usr/src/uts/sparc/sys/wdt.h usr/src/uts/sun4/os/cpu_states.c usr/src/uts/sun4u/os/mach_cpu_states.c usr/src/uts/sun4v/Makefile.files usr/src/uts/sun4v/io/hardclk.c usr/src/uts/sun4v/ml/hcall.s usr/src/uts/sun4v/os/mach_cpu_states.c usr/src/uts/sun4v/os/wdt.c usr/src/uts/sun4v/sys/hypervisor_api.h
diffstat 10 files changed, 450 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/os/clock.c	Mon May 22 15:43:31 2006 -0700
+++ b/usr/src/uts/common/os/clock.c	Mon May 22 18:36:17 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -24,7 +23,7 @@
 
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -70,6 +69,10 @@
 #include <sys/chip.h>
 #include <sys/sdt.h>
 
+#ifdef __sparc
+#include <sys/wdt.h>
+#endif
+
 /*
  * for NTP support
  */
@@ -1851,6 +1854,10 @@
 		lbolt += hz;
 		lbolt64 += hz;
 
+#ifdef __sparc
+		watchdog_pat();
+#endif
+
 		if (!deadman_panic_timers)
 			return; /* allow all timers to be manually disabled */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/sys/wdt.h	Mon May 22 18:36:17 2006 -0700
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_WDT_H
+#define	_SYS_WDT_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+extern void watchdog_init(void);
+extern void watchdog_pat(void);
+extern void watchdog_suspend(void);
+extern void watchdog_resume(void);
+extern void watchdog_clear(void);
+extern void restore_watchdog_on_entry(void);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_WDT_H */
--- a/usr/src/uts/sun4/os/cpu_states.c	Mon May 22 15:43:31 2006 -0700
+++ b/usr/src/uts/sun4/os/cpu_states.c	Mon May 22 18:36:17 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,6 +36,7 @@
 #include <sys/ivintr.h>
 #include <sys/kdi.h>
 #include <sys/callb.h>
+#include <sys/wdt.h>
 
 #ifdef	TRAPTRACE
 #include <sys/traptrace.h>
@@ -63,10 +63,8 @@
 /*
  * Platform tunable to disable the h/w watchdog timer.
  */
-int disable_watchdog_on_exit = 0;
 extern void clear_watchdog_on_exit(void);
 
-
 /*
  * On sun4u platform, abort_sequence_enter() can be called at high PIL
  * and we can't afford to acquire any adaptive mutex or use any
@@ -265,6 +263,8 @@
 	else
 		prom_enter_mon();
 
+	restore_watchdog_on_entry();
+
 	curthread->t_pcb = old_pcb;
 	splx(s);
 	pm_cfb_rele();
--- a/usr/src/uts/sun4u/os/mach_cpu_states.c	Mon May 22 15:43:31 2006 -0700
+++ b/usr/src/uts/sun4u/os/mach_cpu_states.c	Mon May 22 18:36:17 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -50,7 +49,7 @@
 
 extern u_longlong_t	gettick();
 static void reboot_machine(char *);
-extern int disable_watchdog_on_exit;
+int disable_watchdog_on_exit = 0;
 
 /*
  * Machine dependent code to reboot.
@@ -434,6 +433,14 @@
 	}
 }
 
+/*
+ * This null routine is only used by sun4v watchdog timer support.
+ */
+void
+restore_watchdog_on_entry(void)
+{
+}
+
 int
 kdi_watchdog_disable(void)
 {
@@ -456,6 +463,46 @@
 	}
 }
 
+/*
+ * This null routine is only used by sun4v watchdog timer support.
+ */
+void
+watchdog_init(void)
+{
+}
+
+/*
+ * This null routine is only used by sun4v watchdog timer support.
+ */
+void
+watchdog_pat(void)
+{
+}
+
+/*
+ * This null routine is only used by sun4v watchdog timer support.
+ */
+void
+watchdog_suspend(void)
+{
+}
+
+/*
+ * This null routine is only used by sun4v watchdog timer support.
+ */
+void
+watchdog_resume(void)
+{
+}
+
+/*
+ * This null routine is only used by sun4v watchdog timer support.
+ */
+void
+watchdog_clear(void)
+{
+}
+
 /*ARGSUSED*/
 void
 mach_dump_buffer_init(void)
--- a/usr/src/uts/sun4v/Makefile.files	Mon May 22 15:43:31 2006 -0700
+++ b/usr/src/uts/sun4v/Makefile.files	Mon May 22 18:36:17 2006 -0700
@@ -78,6 +78,7 @@
 CORE_OBJS +=	promif_version.o
 CORE_OBJS +=	sfmmu_kdi.o
 CORE_OBJS +=	swtch.o
+CORE_OBJS +=	wdt.o
 CORE_OBJS +=	xhat_sfmmu.o
 
 CORE_OBJS +=	mdesc_diff.o
--- a/usr/src/uts/sun4v/io/hardclk.c	Mon May 22 15:43:31 2006 -0700
+++ b/usr/src/uts/sun4v/io/hardclk.c	Mon May 22 18:36:17 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -49,6 +48,7 @@
 #include <sys/atomic.h>
 #include <sys/cpu_module.h>
 #include <sys/hypervisor_api.h>
+#include <sys/wdt.h>
 
 uint_t sys_clock_mhz = 0;
 uint64_t sys_tick_freq = 0;
@@ -61,6 +61,10 @@
 void
 clkstart(void)
 {
+	/*
+	 * Now is a good time to activate hardware watchdog.
+	 */
+	watchdog_init();
 }
 
 /*
@@ -146,6 +150,12 @@
 	int i;
 	unsigned int spl_old;
 	uint64_t ret;
+
+	/*
+	 * Pat the watchdog timer regularly.
+	 */
+	watchdog_pat();
+
 	/*
 	 * Make sure we don't get preempted
 	 * while getting the tod value.
--- a/usr/src/uts/sun4v/ml/hcall.s	Mon May 22 15:43:31 2006 -0700
+++ b/usr/src/uts/sun4v/ml/hcall.s	Mon May 22 18:36:17 2006 -0700
@@ -321,6 +321,11 @@
     uint64_t *supported_minor)
 { return (0); }
 
+/*ARGSUSED*/	
+uint64_t
+hv_mach_set_watchdog(uint64_t timeout, uint64_t *time_remaining)
+{ return (0); }
+
 #else	/* lint || __lint */
 
 	/*
@@ -658,6 +663,20 @@
 	stx	%o1, [%o2]
 	SET_SIZE(hv_dump_buf_update)
 
+	/*
+	 * arg0 - timeout value (%o0)
+	 *
+	 * ret0 - status (%o0)
+	 * ret1 - time_remaining (%o1)
+	 * hv_mach_set_watchdog(uint64_t timeout, uint64_t *time_remaining)
+	 */
+	ENTRY(hv_mach_set_watchdog)
+	mov	%o1, %o2
+	mov	MACH_SET_WATCHDOG, %o5
+	ta	FAST_TRAP
+	retl
+	stx	%o1, [%o2]
+	SET_SIZE(hv_mach_set_watchdog)
 
 	/*
 	 * For memory scrub
--- a/usr/src/uts/sun4v/os/mach_cpu_states.c	Mon May 22 15:43:31 2006 -0700
+++ b/usr/src/uts/sun4v/os/mach_cpu_states.c	Mon May 22 18:36:17 2006 -0700
@@ -50,6 +50,7 @@
 #include <sys/callb.h>
 #include <sys/mdesc.h>
 #include <sys/mach_descrip.h>
+#include <sys/wdt.h>
 
 /*
  * hvdump_buf_va is a pointer to the currently-configured hvdump_buf.
@@ -151,6 +152,8 @@
 	 */
 	reset_leaves();
 
+	watchdog_clear();
+
 	if (fcn == AD_HALT) {
 		halt((char *)NULL);
 	} else if (fcn == AD_POWEROFF) {
@@ -467,23 +470,32 @@
 void
 clear_watchdog_on_exit(void)
 {
+	prom_printf("Debugging requested; hardware watchdog suspended.\n");
+	(void) watchdog_suspend();
 }
 
+/*
+ * Restore the watchdog timer when returning from a debugger
+ * after a panic or L1-A and resume watchdog pat.
+ */
 void
-clear_watchdog_timer(void)
+restore_watchdog_on_entry()
 {
+	watchdog_resume();
 }
 
 int
 kdi_watchdog_disable(void)
 {
-	return (0);	/* sun4v has no watchdog */
+	watchdog_suspend();
+
+	return (0);
 }
 
 void
 kdi_watchdog_restore(void)
 {
-	/* nothing to do -- no watchdog to re-enable */
+	watchdog_resume();
 }
 
 void
@@ -977,6 +989,25 @@
 	kdi->mkdi_get_stick = kdi_get_stick;
 }
 
+static void
+sun4v_system_claim(void)
+{
+	watchdog_suspend();
+}
+
+static void
+sun4v_system_release(void)
+{
+	watchdog_resume();
+}
+
+void
+plat_kdi_init(kdi_t *kdi)
+{
+	kdi->pkdi_system_claim = sun4v_system_claim;
+	kdi->pkdi_system_release = sun4v_system_release;
+}
+
 /*
  * Routine to return memory information associated
  * with a physical address and syndrome.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sun4v/os/wdt.c	Mon May 22 18:36:17 2006 -0700
@@ -0,0 +1,266 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/hsvc.h>
+#include <sys/wdt.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+#include <sys/sysmacros.h>
+#include <sys/hypervisor_api.h>
+#include <sys/mach_descrip.h>
+#include <sys/mdesc.h>
+
+#define	WDT_ON			1
+#define	WDT_OFF			0
+#define	WDT_DEFAULT_RESOLUTION	10		/* 10 milliseconds */
+/*
+ * MILLISEC defines the number of milliseconds in a second.
+ */
+#define	WDT_MAX_RESOLUTION	(1 * MILLISEC)	/* 1 second */
+#define	WDT_REGULAR_TIMEOUT	(10 * MILLISEC)	/* 10 seconds */
+#define	WDT_LONG_TIMEOUT	(60 * MILLISEC)	/* 60 seconds */
+#define	WDT_MIN_COREAPI_MAJOR	1
+#define	WDT_MIN_COREAPI_MINOR	1
+/*
+ * The ratio to calculate the watchdog timer pat interval.
+ */
+#define	WDT_PAT_INTERVAL(x)	((x) / 2)
+
+int watchdog_enabled = 1;
+
+static void set_watchdog_pat_intervals(void);
+static void config_watchdog(uint64_t, int);
+
+/*
+ * Flag used to pat/suspend/resume the watchdog timer.
+ */
+static int watchdog_activated = WDT_OFF;
+static uint64_t watchdog_regular_timeout = WDT_REGULAR_TIMEOUT;
+static uint64_t watchdog_long_timeout = 0;
+static uint64_t watchdog_resolution = WDT_DEFAULT_RESOLUTION;
+static int64_t watchdog_last_pat = 0;	/* The time of last pat. */
+static int64_t last_pat_interval = 0;	/* The pat interval of last pat. */
+static int64_t watchdog_long_pat_interval = 0;
+static int64_t watchdog_regular_pat_interval = 0;
+
+void
+watchdog_init(void)
+{
+	int num_nodes;
+	int nplat;
+	md_t *mdp;
+	mde_cookie_t *listp = NULL;
+	int listsz;
+	uint64_t major;
+	uint64_t minor;
+	uint64_t watchdog_max_timeout;
+
+	if (!watchdog_enabled) {
+		return;
+	}
+
+	if (hsvc_version(HSVC_GROUP_CORE, &major, &minor) != 0 ||
+		major != WDT_MIN_COREAPI_MAJOR ||
+		minor < WDT_MIN_COREAPI_MINOR) {
+		cmn_err(CE_NOTE, "Disabling watchdog as watchdog services are "
+			"not available\n");
+		watchdog_enabled = 0;
+		return;
+	}
+
+	/*
+	 * Get the watchdog-max-timeout and watchdog-resolution MD properties.
+	 */
+	if ((mdp = md_get_handle()) == NULL) {
+		cmn_err(CE_WARN, "Unable to initialize machine description, "
+			"watchdog is disabled.");
+		watchdog_enabled = 0;
+		return;
+	}
+
+	num_nodes = md_node_count(mdp);
+	ASSERT(num_nodes > 0);
+
+	listsz = num_nodes * sizeof (mde_cookie_t);
+	listp = kmem_zalloc(listsz, KM_SLEEP);
+
+	nplat = md_scan_dag(mdp, md_root_node(mdp),
+		md_find_name(mdp, "platform"), md_find_name(mdp, "fwd"), listp);
+
+	ASSERT(nplat == 1);
+
+	if (md_get_prop_val(mdp, listp[0], "watchdog-max-timeout",
+		&watchdog_max_timeout)) {
+		cmn_err(CE_WARN, "Cannot read watchdog-max-timeout, watchdog "
+			"is disabled.");
+		watchdog_enabled = 0;
+		kmem_free(listp, listsz);
+		(void) md_fini_handle(mdp);
+		return;
+	}
+
+	if (watchdog_max_timeout < WDT_REGULAR_TIMEOUT) {
+		cmn_err(CE_WARN, "Invalid watchdog-max-timeout value, watchdog "
+			"is disabled.");
+		watchdog_enabled = 0;
+		kmem_free(listp, listsz);
+		(void) md_fini_handle(mdp);
+		return;
+	}
+
+	if (md_get_prop_val(mdp, listp[0], "watchdog-resolution",
+		&watchdog_resolution)) {
+		cmn_err(CE_WARN, "Cannot read watchdog-resolution, watchdog "
+			"is disabled.");
+		watchdog_enabled = 0;
+		kmem_free(listp, listsz);
+		(void) md_fini_handle(mdp);
+		return;
+	}
+
+	if (watchdog_resolution == 0 ||
+		watchdog_resolution > WDT_MAX_RESOLUTION) {
+		watchdog_resolution = WDT_DEFAULT_RESOLUTION;
+	}
+	kmem_free(listp, listsz);
+	(void) md_fini_handle(mdp);
+
+	watchdog_long_timeout = MIN(WDT_LONG_TIMEOUT, watchdog_max_timeout);
+
+	/*
+	 * round the timeout to the nearest smaller value.
+	 */
+	watchdog_long_timeout -=
+		watchdog_long_timeout % watchdog_resolution;
+	watchdog_regular_timeout -=
+		watchdog_regular_timeout % watchdog_resolution;
+	set_watchdog_pat_intervals();
+
+	config_watchdog(watchdog_regular_timeout, WDT_ON);
+}
+
+/*
+ * Pat the watchdog timer periodically, for regular pat in tod_get when
+ * the kernel runs normally and long pat in deadman when panicking.
+ */
+void
+watchdog_pat()
+{
+	int64_t pat_interval;
+	int64_t current_lbolt64;
+	uint64_t timeout;
+
+	if (watchdog_enabled && watchdog_activated) {
+		if (panicstr) {
+			/*
+			 * long timeout is only used while panicking.
+			 */
+			timeout = watchdog_long_timeout;
+			pat_interval = watchdog_long_pat_interval;
+		} else {
+			timeout = watchdog_regular_timeout;
+			pat_interval = watchdog_regular_pat_interval;
+		}
+
+		current_lbolt64 = lbolt64;
+
+		if ((current_lbolt64 - watchdog_last_pat)
+			>= last_pat_interval) {
+			/*
+			 * Pat the watchdog via hv api:
+			 */
+			config_watchdog(timeout, WDT_ON);
+
+			last_pat_interval = pat_interval;
+			watchdog_last_pat = current_lbolt64;
+		}
+	}
+}
+
+/*
+ * We don't save/restore the remaining watchdog timeout time at present.
+ */
+void
+watchdog_suspend()
+{
+	if (watchdog_enabled && watchdog_activated) {
+		config_watchdog(0, WDT_OFF);
+	}
+}
+
+/*
+ * We don't save/restore the remaining watchdog timeout time at present.
+ */
+void
+watchdog_resume()
+{
+	if (watchdog_enabled && !watchdog_activated) {
+		if (panicstr) {
+			config_watchdog(watchdog_long_timeout, WDT_ON);
+		} else {
+			config_watchdog(watchdog_regular_timeout, WDT_ON);
+		}
+	}
+}
+
+void
+watchdog_clear()
+{
+	if (watchdog_enabled && watchdog_activated) {
+		config_watchdog(0, WDT_OFF);
+	}
+}
+
+/*
+ * Set the pat intervals for both regular (when Solaris is running),
+ * and long timeout (i.e., when panicking) cases.
+ */
+static void
+set_watchdog_pat_intervals(void)
+{
+	watchdog_regular_pat_interval =
+		MSEC_TO_TICK(WDT_PAT_INTERVAL(watchdog_regular_timeout));
+	watchdog_long_pat_interval =
+		MSEC_TO_TICK(WDT_PAT_INTERVAL(watchdog_long_timeout));
+}
+
+static void
+config_watchdog(uint64_t timeout, int new_state)
+{
+	uint64_t time_remaining;
+	uint64_t ret;
+
+	watchdog_activated = new_state;
+	ret = hv_mach_set_watchdog(timeout, &time_remaining);
+	if (ret != H_EOK) {
+		cmn_err(CE_WARN, "Failed to operate on the watchdog. "
+			"Error = 0x%lx", ret);
+		watchdog_enabled = 0;
+	}
+}
--- a/usr/src/uts/sun4v/sys/hypervisor_api.h	Mon May 22 15:43:31 2006 -0700
+++ b/usr/src/uts/sun4v/sys/hypervisor_api.h	Mon May 22 18:36:17 2006 -0700
@@ -90,6 +90,7 @@
 #define	HV_MACH_EXIT		0x00
 #define	HV_MACH_DESC		0x01
 #define	HV_MACH_SIR		0x02
+#define	MACH_SET_WATCHDOG	0x05
 
 #define	HV_CPU_START		0x10
 #define	HV_CPU_STOP		0x11
@@ -352,6 +353,7 @@
 extern uint64_t hv_ttrace_enable(uint64_t, uint64_t *);
 extern uint64_t hv_ttrace_freeze(uint64_t, uint64_t *);
 extern uint64_t hv_dump_buf_update(uint64_t, uint64_t, uint64_t *);
+extern uint64_t hv_mach_set_watchdog(uint64_t, uint64_t *);
 
 extern int64_t hv_cnputchar(uint8_t);
 extern int64_t hv_cngetchar(uint8_t *);