xref: /onnv-gate/usr/src/uts/sun4u/io/todsg.c (revision 7696:21f5c73c0c15)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
5*7696SRichard.Bean@Sun.COM  * Common Development and Distribution License (the "License").
6*7696SRichard.Bean@Sun.COM  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel /*
22*7696SRichard.Bean@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
231708Sstevel  * Use is subject to license terms.
241708Sstevel  */
251708Sstevel 
261708Sstevel /*
271708Sstevel  * tod driver module for Serengeti
281708Sstevel  * This module implements a soft tod since
291708Sstevel  * Serengeti has no tod part.
301708Sstevel  */
311708Sstevel 
321708Sstevel #include <sys/modctl.h>
331708Sstevel #include <sys/systm.h>
341708Sstevel #include <sys/cpuvar.h>
351708Sstevel #include <sys/promif.h>
361708Sstevel #include <sys/sgsbbc_iosram.h>
371708Sstevel #include <sys/todsg.h>
381708Sstevel #include <sys/cmn_err.h>
391708Sstevel #include <sys/time.h>
401708Sstevel #include <sys/sysmacros.h>
411708Sstevel #include <sys/clock.h>
421708Sstevel 
431708Sstevel #if defined(DEBUG) || defined(lint)
441708Sstevel static int todsg_debug = 0;
451708Sstevel #define	DCMNERR if (todsg_debug) cmn_err
461708Sstevel #else
471708Sstevel #define	DCMNERR
481708Sstevel #endif /* DEBUG */
491708Sstevel 
501708Sstevel #define	OFFSET(base, field)	((char *)&base.field - (char *)&base)
511708Sstevel #define	SC_DOWN_COUNT_THRESHOLD	2
521708Sstevel #define	SC_TOD_MIN_REV		2
531708Sstevel 
541708Sstevel static timestruc_t	todsg_get(void);
551708Sstevel static void		todsg_set(timestruc_t);
561708Sstevel static uint32_t		todsg_set_watchdog_timer(uint_t);
571708Sstevel static uint32_t		todsg_clear_watchdog_timer(void);
581708Sstevel static void		todsg_set_power_alarm(timestruc_t);
591708Sstevel static void		todsg_clear_power_alarm(void);
601708Sstevel static uint64_t		todsg_get_cpufrequency(void);
611708Sstevel static int 		update_heartbeat(void);
621708Sstevel static int		verify_sc_tod_version(void);
631708Sstevel static int 		update_tod_skew(time_t skew);
641708Sstevel 
651708Sstevel static uint32_t i_am_alive = 0;
661708Sstevel static uint32_t sc_tod_version = 0;
671708Sstevel static time_t 	skew_adjust = 0;
681708Sstevel static int 	is_sc_down = 0;
691708Sstevel static int	adjust_sc_down = 0;
701708Sstevel 
711708Sstevel /*
721708Sstevel  * Module linkage information for the kernel.
731708Sstevel  */
741708Sstevel static struct modlmisc modlmisc = {
75*7696SRichard.Bean@Sun.COM 	&mod_miscops, "Serengeti tod module"
761708Sstevel };
771708Sstevel 
781708Sstevel static struct modlinkage modlinkage = {
791708Sstevel 	MODREV_1, (void *)&modlmisc, NULL
801708Sstevel };
811708Sstevel 
821708Sstevel int
831708Sstevel _init(void)
841708Sstevel {
851708Sstevel 
861708Sstevel 	DCMNERR(CE_NOTE, "todsg:_init(): begins");
871708Sstevel 
881708Sstevel 	if (strcmp(tod_module_name, "todsg") == 0) {
891708Sstevel 		time_t ssc_time = (time_t)0;
901708Sstevel 		char obp_string[80];
911708Sstevel 
921708Sstevel 		/*
931708Sstevel 		 * To obtain the initial start of day time, we use an
941708Sstevel 		 * OBP callback; this is because the iosram is not yet
951708Sstevel 		 * accessible from the OS at this early stage of startup.
961708Sstevel 		 */
971708Sstevel 
981708Sstevel 		/*
991708Sstevel 		 * Set the string to pass to OBP
1001708Sstevel 		 */
1011708Sstevel 		(void) sprintf(obp_string,
1021708Sstevel 			"h# %p \" unix-get-tod\" $find if execute else "
1031708Sstevel 			"3drop then",
1041708Sstevel 			(void *)&ssc_time);
1051708Sstevel 
1061708Sstevel 		prom_interpret(obp_string, 0, 0, 0, 0, 0);
1071708Sstevel 
1081708Sstevel 		if (ssc_time == (time_t)0) {
1091708Sstevel 			cmn_err(CE_WARN, "Initial date is invalid. "
1101708Sstevel 				"This can be caused by older firmware.");
1111708Sstevel 			cmn_err(CE_CONT, "Please flashupdate the System "
1121708Sstevel 				"Controller firmware to the latest version.\n");
1131708Sstevel 			cmn_err(CE_CONT, "Attempting to set the date and time "
1141708Sstevel 				"based on the last shutdown.\n");
1151708Sstevel 			cmn_err(CE_CONT, "Please inspect the date and time and "
1161708Sstevel 				"correct if necessary.\n");
1171708Sstevel 		}
1181708Sstevel 
1191708Sstevel 		hrestime.tv_sec = ssc_time;
1201708Sstevel 
1211708Sstevel 		DCMNERR(CE_NOTE, "todsg: _init(): time from OBP 0x%lX",
1221708Sstevel 				ssc_time);
1231708Sstevel 		/*
1241708Sstevel 		 * Verify whether the received date/clock has overflowed
1251708Sstevel 		 * an integer(32bit), so that we capture any corrupted
1261708Sstevel 		 * date from SC, thereby preventing boot failure.
1271708Sstevel 		 */
1281708Sstevel 		if (TIMESPEC_OVERFLOW(&hrestime)) {
1291708Sstevel 			cmn_err(CE_WARN, "Date overflow detected.");
1301708Sstevel 			cmn_err(CE_CONT, "Attempting to set the date and time "
1311708Sstevel 				"based on the last shutdown.\n");
1321708Sstevel 			cmn_err(CE_CONT, "Please inspect the date and time and "
1331708Sstevel 				"correct if necessary.\n");
1341708Sstevel 
1351708Sstevel 			/*
1361708Sstevel 			 * By setting hrestime.tv_sec to zero
1371708Sstevel 			 * we force the vfs_mountroot() to set
1381708Sstevel 			 * the date from the last shutdown.
1391708Sstevel 			 */
1401708Sstevel 			hrestime.tv_sec = (time_t)0;
1411708Sstevel 			/*
1421708Sstevel 			 * Save the skew so that we can update
1431708Sstevel 			 * IOSRAM when it becomes accessible.
1441708Sstevel 			 */
1451708Sstevel 			skew_adjust = -ssc_time;
1461708Sstevel 		}
1471708Sstevel 
1481708Sstevel 		DCMNERR(CE_NOTE, "todsg:_init(): set tod_ops");
1491708Sstevel 
1501708Sstevel 		tod_ops.tod_get = todsg_get;
1511708Sstevel 		tod_ops.tod_set = todsg_set;
1521708Sstevel 		tod_ops.tod_set_watchdog_timer = todsg_set_watchdog_timer;
1531708Sstevel 		tod_ops.tod_clear_watchdog_timer = todsg_clear_watchdog_timer;
1541708Sstevel 		tod_ops.tod_set_power_alarm = todsg_set_power_alarm;
1551708Sstevel 		tod_ops.tod_clear_power_alarm = todsg_clear_power_alarm;
1561708Sstevel 		tod_ops.tod_get_cpufrequency = todsg_get_cpufrequency;
1571708Sstevel 	}
1581708Sstevel 
1591708Sstevel 	return (mod_install(&modlinkage));
1601708Sstevel 
1611708Sstevel }
1621708Sstevel 
1631708Sstevel int
1641708Sstevel _fini(void)
1651708Sstevel {
1661708Sstevel 	if (strcmp(tod_module_name, "todsg") == 0)
1671708Sstevel 		return (EBUSY);
1681708Sstevel 	else
1691708Sstevel 		return (mod_remove(&modlinkage));
1701708Sstevel }
1711708Sstevel 
1721708Sstevel int
1731708Sstevel _info(struct modinfo *modinfop)
1741708Sstevel {
1751708Sstevel 	return (mod_info(&modlinkage, modinfop));
1761708Sstevel }
1771708Sstevel 
1781708Sstevel static int
1791708Sstevel update_heartbeat(void)
1801708Sstevel {
1811708Sstevel 	tod_iosram_t tod_buf;
1821708Sstevel 	int complained = 0;
1831708Sstevel 
1841708Sstevel 	/* Update the heartbeat */
1851708Sstevel 	if (i_am_alive == UINT32_MAX)
1861708Sstevel 		i_am_alive = 0;
1871708Sstevel 	else
1881708Sstevel 		i_am_alive++;
1891708Sstevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_i_am_alive),
1901708Sstevel 			(char *)&i_am_alive, sizeof (uint32_t))) {
1911708Sstevel 		complained++;
1921708Sstevel 		cmn_err(CE_WARN, "update_heartbeat(): write heartbeat failed");
1931708Sstevel 	}
1941708Sstevel 	return (complained);
1951708Sstevel }
1961708Sstevel 
1971708Sstevel static int
1981708Sstevel verify_sc_tod_version(void)
1991708Sstevel {
2001708Sstevel 	uint32_t magic;
2011708Sstevel 	tod_iosram_t tod_buf;
2021708Sstevel 
2031708Sstevel 	if (!todsg_use_sc)
2041708Sstevel 		return (FALSE);
2051708Sstevel 	/*
2061708Sstevel 	 * read tod_version only when the first time and
2071708Sstevel 	 * when there has been a previous sc down time
2081708Sstevel 	 */
2091708Sstevel 	if (!sc_tod_version || is_sc_down >= SC_DOWN_COUNT_THRESHOLD) {
2101708Sstevel 		if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_magic),
2111708Sstevel 			(char *)&magic, sizeof (uint32_t)) ||
2121708Sstevel 				magic != TODSG_MAGIC) {
2131708Sstevel 			cmn_err(CE_WARN, "get_sc_tod_version(): "
2141708Sstevel 						"TOD SRAM magic error");
2151708Sstevel 			return (FALSE);
2161708Sstevel 		}
2171708Sstevel 		if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_version),
2181708Sstevel 			(char *)&sc_tod_version, sizeof (uint32_t))) {
2191708Sstevel 			cmn_err(CE_WARN, "get_sc_tod_version(): "
2201708Sstevel 				"read tod version failed");
2211708Sstevel 			sc_tod_version = 0;
2221708Sstevel 			return (FALSE);
2231708Sstevel 		}
2241708Sstevel 	}
2251708Sstevel 	if (sc_tod_version >= SC_TOD_MIN_REV) {
2261708Sstevel 		return (TRUE);
2271708Sstevel 	} else {
2281708Sstevel 		todsg_use_sc = 0;
2291708Sstevel 		cmn_err(CE_WARN,
2301708Sstevel 			"todsg_get(): incorrect firmware version, "
2311708Sstevel 			"(%d): expected version >= %d.",
2321708Sstevel 			sc_tod_version, SC_TOD_MIN_REV);
2331708Sstevel 	}
2341708Sstevel 	return (FALSE);
2351708Sstevel }
2361708Sstevel 
2371708Sstevel static int
2381708Sstevel update_tod_skew(time_t skew)
2391708Sstevel {
2401708Sstevel 	time_t domain_skew;
2411708Sstevel 	tod_iosram_t tod_buf;
2421708Sstevel 	int complained = 0;
2431708Sstevel 
2441708Sstevel 	DCMNERR(CE_NOTE, "update_tod_skew(): skew  0x%lX", skew);
2451708Sstevel 
2461708Sstevel 	if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_domain_skew),
2471708Sstevel 			(char *)&domain_skew, sizeof (time_t))) {
2481708Sstevel 		complained++;
2491708Sstevel 		cmn_err(CE_WARN, "update_tod_skew(): "
2501708Sstevel 				"read tod domain skew failed");
2511708Sstevel 	}
2521708Sstevel 	domain_skew += skew;
2531708Sstevel 	/* we shall update the skew_adjust too now */
2541708Sstevel 	domain_skew += skew_adjust;
2551708Sstevel 	if (!complained && iosram_write(SBBC_TOD_KEY,
2561708Sstevel 			OFFSET(tod_buf, tod_domain_skew),
2571708Sstevel 				(char *)&domain_skew, sizeof (time_t))) {
2581708Sstevel 		complained++;
2591708Sstevel 		cmn_err(CE_WARN, "update_tod_skew(): "
2601708Sstevel 				"write domain skew failed");
2611708Sstevel 	}
2621708Sstevel 	if (!complained)
2631708Sstevel 		skew_adjust = 0;
2641708Sstevel 	return (complained);
2651708Sstevel }
2661708Sstevel 
2671708Sstevel 
2681708Sstevel /*
2691708Sstevel  * Return time value read from IOSRAM.
2701708Sstevel  * Must be called with tod_lock held.
2711708Sstevel  */
2721708Sstevel static timestruc_t
2731708Sstevel todsg_get(void)
2741708Sstevel {
2751708Sstevel 	tod_iosram_t tod_buf;
2761708Sstevel 	time_t seconds;
2771708Sstevel 	time_t domain_skew;
2781708Sstevel 	int complained = 0;
2791708Sstevel 	static time_t pre_seconds = (time_t)0;
2801708Sstevel 
2811708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
2821708Sstevel 
2831708Sstevel 	if (!verify_sc_tod_version()) {
2841708Sstevel 		/* if we can't use SC */
2851708Sstevel 		goto return_hrestime;
2861708Sstevel 	}
2871708Sstevel 	if (watchdog_activated != 0 || watchdog_enable != 0)
2881708Sstevel 		complained = update_heartbeat();
2891708Sstevel 	if (!complained && (iosram_read(SBBC_TOD_KEY,
2901708Sstevel 			OFFSET(tod_buf, tod_get_value),
2911708Sstevel 			(char *)&seconds, sizeof (time_t)))) {
2921708Sstevel 		complained++;
2931708Sstevel 		cmn_err(CE_WARN, "todsg_get(): read 64-bit tod value failed");
2941708Sstevel 	}
2951708Sstevel 	if (!complained && skew_adjust)  {
2961708Sstevel 		/*
2971708Sstevel 		 * This is our first chance to update IOSRAM
2981708Sstevel 		 * with local copy of the skew,  so update it.
2991708Sstevel 		 */
3001708Sstevel 		complained = update_tod_skew(0);
3011708Sstevel 	}
3021708Sstevel 	if (!complained && iosram_read(SBBC_TOD_KEY,
3031708Sstevel 			OFFSET(tod_buf, tod_domain_skew),
3041708Sstevel 			(char *)&domain_skew, sizeof (time_t))) {
3051708Sstevel 		complained++;
3061708Sstevel 		cmn_err(CE_WARN, "todsg_get(): read tod domain skew failed");
3071708Sstevel 	}
3081708Sstevel 
3091708Sstevel 	if (complained) {
3101708Sstevel 		cmn_err(CE_WARN, "todsg_get(): turned off using tod");
3111708Sstevel 		todsg_use_sc = 0;
3121708Sstevel 		goto return_hrestime;
3131708Sstevel 	}
3141708Sstevel 
3151708Sstevel 	/*
3161708Sstevel 	 * If the SC gets rebooted, and we are using NTP, then we need
3171708Sstevel 	 * to sync the IOSRAM to hrestime when the SC comes back.  We
3181708Sstevel 	 * can determine that either NTP slew (or date -a) was called if
3191708Sstevel 	 * the global timedelta was non-zero at any point while the SC
3201708Sstevel 	 * was away.  If timedelta remains zero throughout, then the
3211708Sstevel 	 * default action will be to sync hrestime to IOSRAM
3221708Sstevel 	 */
3231708Sstevel 	if (seconds != pre_seconds) {	/* SC still alive */
3241708Sstevel 		pre_seconds = seconds;
3251708Sstevel 		if (is_sc_down >= SC_DOWN_COUNT_THRESHOLD && adjust_sc_down) {
3261708Sstevel 			skew_adjust = hrestime.tv_sec - (seconds + domain_skew);
3271708Sstevel 			complained = update_tod_skew(0);
3281708Sstevel 			if (!complained && (iosram_read(SBBC_TOD_KEY,
3291708Sstevel 				OFFSET(tod_buf, tod_domain_skew),
3301708Sstevel 				(char *)&domain_skew, sizeof (time_t)))) {
3311708Sstevel 				complained++;
3321708Sstevel 				cmn_err(CE_WARN, "todsg_get(): "
3331708Sstevel 					"read tod domain skew failed");
3341708Sstevel 			}
3351708Sstevel 		}
3361708Sstevel 		is_sc_down = 0;
3371708Sstevel 		adjust_sc_down = 0;
3381708Sstevel 
3391708Sstevel 		/*
3401708Sstevel 		 * If complained then domain_skew is invalid.
3411708Sstevel 		 * Hand back hrestime instead.
3421708Sstevel 		 */
3431708Sstevel 		if (!complained) {
3441708Sstevel 			timestruc_t ts = {0, 0};
3451708Sstevel 			ts.tv_sec = seconds + domain_skew;
3461708Sstevel 			return (ts);
3471708Sstevel 		} else {
3481708Sstevel 			goto return_hrestime;
3491708Sstevel 		}
3501708Sstevel 	}
3511708Sstevel 
3521708Sstevel 	/* SC/TOD is down */
3531708Sstevel 	is_sc_down++;
3541708Sstevel 	if (timedelta != 0) {
3551708Sstevel 		adjust_sc_down = 1;
3561708Sstevel 	}
3571708Sstevel 
3581708Sstevel return_hrestime:
3591708Sstevel 	/*
3601708Sstevel 	 * We need to inform the tod_validate code to stop checking till
3611708Sstevel 	 * SC come back up again. Note that we will return hrestime below
3621708Sstevel 	 * which can be different that the previous TOD value we returned
3631708Sstevel 	 */
3641708Sstevel 	tod_fault_reset();
3651708Sstevel 	return (hrestime);
3661708Sstevel }
3671708Sstevel 
3681708Sstevel static void
3691708Sstevel todsg_set(timestruc_t ts)
3701708Sstevel {
3711708Sstevel 	int complained = 0;
3721708Sstevel 	tod_iosram_t tod_buf;
3731708Sstevel 	time_t domain_skew;
3741708Sstevel 	time_t seconds;
3751708Sstevel 	time_t hwtod;
3761708Sstevel 
3771708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
3781708Sstevel 
3791708Sstevel 	if (!verify_sc_tod_version()) {
3801708Sstevel 		/* if we can't use SC */
3811708Sstevel 		return;
3821708Sstevel 	}
3831708Sstevel 	/*
3841708Sstevel 	 * If the SC is down just note the fact that we should
3851708Sstevel 	 * have adjusted the hardware skew which caters for calls
3861708Sstevel 	 * to stime(). (eg NTP step, as opposed to NTP skew)
3871708Sstevel 	 */
3881708Sstevel 	if (is_sc_down) {
3891708Sstevel 		adjust_sc_down = 1;
3901708Sstevel 		return;
3911708Sstevel 	}
3921708Sstevel 	/*
3931708Sstevel 	 * reason to update i_am_alive here:
3941708Sstevel 	 * To work around a generic Solaris bug that can
3951708Sstevel 	 * cause tod_get() to be starved by too frequent
3961708Sstevel 	 * calls to the stime() system call.
3971708Sstevel 	 */
3981708Sstevel 	if (watchdog_activated != 0 || watchdog_enable != 0)
3991708Sstevel 		complained = update_heartbeat();
4001708Sstevel 
4011708Sstevel 	/*
4021708Sstevel 	 * We are passed hrestime from clock.c so we need to read the
4031708Sstevel 	 * IOSRAM for the hardware's idea of the time to see if we need
4041708Sstevel 	 * to update the skew.
4051708Sstevel 	 */
4061708Sstevel 	if (!complained && (iosram_read(SBBC_TOD_KEY,
4071708Sstevel 			OFFSET(tod_buf, tod_get_value),
4081708Sstevel 			(char *)&seconds, sizeof (time_t)))) {
4091708Sstevel 		complained++;
4101708Sstevel 		cmn_err(CE_WARN, "todsg_set(): read 64-bit tod value failed");
4111708Sstevel 	}
4121708Sstevel 
4131708Sstevel 	if (!complained && iosram_read(SBBC_TOD_KEY,
4141708Sstevel 			OFFSET(tod_buf, tod_domain_skew),
4151708Sstevel 			(char *)&domain_skew, sizeof (time_t))) {
4161708Sstevel 		complained++;
4171708Sstevel 		cmn_err(CE_WARN, "todsg_set(): read tod domain skew failed");
4181708Sstevel 	}
4191708Sstevel 
4201708Sstevel 	/*
4211708Sstevel 	 * Only update the skew if the time passed differs from
4221708Sstevel 	 * what the hardware thinks & no errors talking to SC
4231708Sstevel 	 */
4241708Sstevel 	if (!complained && (ts.tv_sec != (seconds + domain_skew))) {
4251708Sstevel 		hwtod = seconds + domain_skew;
4261708Sstevel 		complained = update_tod_skew(ts.tv_sec - hwtod);
4271708Sstevel 
4281708Sstevel 		DCMNERR(CE_NOTE, "todsg_set(): set time %lX (%lX)%s",
4291708Sstevel 			ts.tv_sec, hwtod, complained ? " failed" : "");
4301708Sstevel 
4311708Sstevel 	}
4321708Sstevel 
4331708Sstevel 	if (complained) {
4341708Sstevel 		cmn_err(CE_WARN, "todsg_set(): turned off using tod");
4351708Sstevel 		todsg_use_sc = 0;
4361708Sstevel 	}
4371708Sstevel }
4381708Sstevel 
4391708Sstevel static uint32_t
4401708Sstevel todsg_set_watchdog_timer(uint32_t timeoutval)
4411708Sstevel {
4421708Sstevel 	tod_iosram_t tod_buf;
4431708Sstevel 
4441708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
4451708Sstevel 
4461708Sstevel 	if (!verify_sc_tod_version()) {
4471708Sstevel 		DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
4481708Sstevel 			"verify_sc_tod_version failed");
4491708Sstevel 		return (0);
4501708Sstevel 	}
4511708Sstevel 	DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
4521708Sstevel 		"set watchdog timer value = %d", timeoutval);
4531708Sstevel 
4541708Sstevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
4551708Sstevel 			(char *)&timeoutval, sizeof (uint32_t))) {
4561708Sstevel 		DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
4571708Sstevel 			"write new timeout value failed");
4581708Sstevel 		return (0);
4591708Sstevel 	}
4601708Sstevel 	watchdog_activated = 1;
4611708Sstevel 	return (timeoutval);
4621708Sstevel }
4631708Sstevel 
4641708Sstevel static uint32_t
4651708Sstevel todsg_clear_watchdog_timer(void)
4661708Sstevel {
4671708Sstevel 	tod_iosram_t tod_buf;
4681708Sstevel 	uint32_t r_timeout_period;
4691708Sstevel 	uint32_t w_timeout_period;
4701708Sstevel 
4711708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
4721708Sstevel 
4731708Sstevel 	if ((watchdog_activated == 0) || !verify_sc_tod_version()) {
4741708Sstevel 		DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
4751708Sstevel 			"either watchdog not activated or "
4761708Sstevel 			"verify_sc_tod_version failed");
4771708Sstevel 		return (0);
4781708Sstevel 	}
4791708Sstevel 	if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
4801708Sstevel 			(char *)&r_timeout_period, sizeof (uint32_t))) {
4811708Sstevel 		DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
4821708Sstevel 			"read timeout value failed");
4831708Sstevel 		return (0);
4841708Sstevel 	}
4851708Sstevel 	DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
4861708Sstevel 		"clear watchdog timer (old value=%d)", r_timeout_period);
4871708Sstevel 	w_timeout_period = 0;
4881708Sstevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
4891708Sstevel 			(char *)&w_timeout_period, sizeof (uint32_t))) {
4901708Sstevel 		DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
4911708Sstevel 			"write zero timeout value failed");
4921708Sstevel 		return (0);
4931708Sstevel 	}
4941708Sstevel 	watchdog_activated = 0;
4951708Sstevel 	return (r_timeout_period);
4961708Sstevel }
4971708Sstevel 
4981708Sstevel /*
4991708Sstevel  * Null function.
5001708Sstevel  */
5011708Sstevel /* ARGSUSED */
5021708Sstevel static void
5031708Sstevel todsg_set_power_alarm(timestruc_t ts)
5041708Sstevel {
5051708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
5061708Sstevel }
5071708Sstevel 
5081708Sstevel /*
5091708Sstevel  * Null function
5101708Sstevel  */
5111708Sstevel static void
5121708Sstevel todsg_clear_power_alarm()
5131708Sstevel {
5141708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
5151708Sstevel }
5161708Sstevel 
5171708Sstevel /*
5181708Sstevel  * Get clock freq from the cpunode
5191708Sstevel  */
5201708Sstevel uint64_t
5211708Sstevel todsg_get_cpufrequency(void)
5221708Sstevel {
5231708Sstevel 
5241708Sstevel 	DCMNERR(CE_NOTE, "todsg_get_cpufrequency(): frequency=%ldMHz",
5251708Sstevel 		cpunodes[CPU->cpu_id].clock_freq/1000000);
5261708Sstevel 
5271708Sstevel 	return (cpunodes[CPU->cpu_id].clock_freq);
5281708Sstevel }
529