xref: /onnv-gate/usr/src/uts/sun4u/io/todsg.c (revision 11752:9c475fee0b48)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
57696SRichard.Bean@Sun.COM  * Common Development and Distribution License (the "License").
67696SRichard.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*11752STrevor.Thompson@Sun.COM  * Copyright 2010 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 = {
757696SRichard.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
_init(void)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,
102*11752STrevor.Thompson@Sun.COM 		    "h# %p \" unix-get-tod\" $find if execute else 3drop then",
103*11752STrevor.Thompson@Sun.COM 		    (void *)&ssc_time);
1041708Sstevel 
1051708Sstevel 		prom_interpret(obp_string, 0, 0, 0, 0, 0);
1061708Sstevel 
1071708Sstevel 		if (ssc_time == (time_t)0) {
1081708Sstevel 			cmn_err(CE_WARN, "Initial date is invalid. "
109*11752STrevor.Thompson@Sun.COM 			    "This can be caused by older firmware.");
1101708Sstevel 			cmn_err(CE_CONT, "Please flashupdate the System "
111*11752STrevor.Thompson@Sun.COM 			    "Controller firmware to the latest version.\n");
1121708Sstevel 			cmn_err(CE_CONT, "Attempting to set the date and time "
113*11752STrevor.Thompson@Sun.COM 			    "based on the last shutdown.\n");
1141708Sstevel 			cmn_err(CE_CONT, "Please inspect the date and time and "
115*11752STrevor.Thompson@Sun.COM 			    "correct if necessary.\n");
1161708Sstevel 		}
1171708Sstevel 
1181708Sstevel 		hrestime.tv_sec = ssc_time;
1191708Sstevel 
1201708Sstevel 		DCMNERR(CE_NOTE, "todsg: _init(): time from OBP 0x%lX",
121*11752STrevor.Thompson@Sun.COM 		    ssc_time);
1221708Sstevel 		/*
1231708Sstevel 		 * Verify whether the received date/clock has overflowed
1241708Sstevel 		 * an integer(32bit), so that we capture any corrupted
1251708Sstevel 		 * date from SC, thereby preventing boot failure.
1261708Sstevel 		 */
1271708Sstevel 		if (TIMESPEC_OVERFLOW(&hrestime)) {
1281708Sstevel 			cmn_err(CE_WARN, "Date overflow detected.");
1291708Sstevel 			cmn_err(CE_CONT, "Attempting to set the date and time "
130*11752STrevor.Thompson@Sun.COM 			    "based on the last shutdown.\n");
1311708Sstevel 			cmn_err(CE_CONT, "Please inspect the date and time and "
132*11752STrevor.Thompson@Sun.COM 			    "correct if necessary.\n");
1331708Sstevel 
1341708Sstevel 			/*
1351708Sstevel 			 * By setting hrestime.tv_sec to zero
1361708Sstevel 			 * we force the vfs_mountroot() to set
1371708Sstevel 			 * the date from the last shutdown.
1381708Sstevel 			 */
1391708Sstevel 			hrestime.tv_sec = (time_t)0;
1401708Sstevel 			/*
1411708Sstevel 			 * Save the skew so that we can update
1421708Sstevel 			 * IOSRAM when it becomes accessible.
1431708Sstevel 			 */
1441708Sstevel 			skew_adjust = -ssc_time;
1451708Sstevel 		}
1461708Sstevel 
1471708Sstevel 		DCMNERR(CE_NOTE, "todsg:_init(): set tod_ops");
1481708Sstevel 
1491708Sstevel 		tod_ops.tod_get = todsg_get;
1501708Sstevel 		tod_ops.tod_set = todsg_set;
1511708Sstevel 		tod_ops.tod_set_watchdog_timer = todsg_set_watchdog_timer;
1521708Sstevel 		tod_ops.tod_clear_watchdog_timer = todsg_clear_watchdog_timer;
1531708Sstevel 		tod_ops.tod_set_power_alarm = todsg_set_power_alarm;
1541708Sstevel 		tod_ops.tod_clear_power_alarm = todsg_clear_power_alarm;
1551708Sstevel 		tod_ops.tod_get_cpufrequency = todsg_get_cpufrequency;
1561708Sstevel 	}
1571708Sstevel 
1581708Sstevel 	return (mod_install(&modlinkage));
1591708Sstevel 
1601708Sstevel }
1611708Sstevel 
1621708Sstevel int
_fini(void)1631708Sstevel _fini(void)
1641708Sstevel {
1651708Sstevel 	if (strcmp(tod_module_name, "todsg") == 0)
1661708Sstevel 		return (EBUSY);
1671708Sstevel 	else
1681708Sstevel 		return (mod_remove(&modlinkage));
1691708Sstevel }
1701708Sstevel 
1711708Sstevel int
_info(struct modinfo * modinfop)1721708Sstevel _info(struct modinfo *modinfop)
1731708Sstevel {
1741708Sstevel 	return (mod_info(&modlinkage, modinfop));
1751708Sstevel }
1761708Sstevel 
1771708Sstevel static int
update_heartbeat(void)1781708Sstevel update_heartbeat(void)
1791708Sstevel {
1801708Sstevel 	tod_iosram_t tod_buf;
1811708Sstevel 	int complained = 0;
1821708Sstevel 
1831708Sstevel 	/* Update the heartbeat */
1841708Sstevel 	if (i_am_alive == UINT32_MAX)
1851708Sstevel 		i_am_alive = 0;
1861708Sstevel 	else
1871708Sstevel 		i_am_alive++;
1881708Sstevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_i_am_alive),
189*11752STrevor.Thompson@Sun.COM 	    (char *)&i_am_alive, sizeof (uint32_t))) {
1901708Sstevel 		complained++;
1911708Sstevel 		cmn_err(CE_WARN, "update_heartbeat(): write heartbeat failed");
1921708Sstevel 	}
1931708Sstevel 	return (complained);
1941708Sstevel }
1951708Sstevel 
1961708Sstevel static int
verify_sc_tod_version(void)1971708Sstevel verify_sc_tod_version(void)
1981708Sstevel {
1991708Sstevel 	uint32_t magic;
2001708Sstevel 	tod_iosram_t tod_buf;
2011708Sstevel 
2021708Sstevel 	if (!todsg_use_sc)
2031708Sstevel 		return (FALSE);
2041708Sstevel 	/*
2051708Sstevel 	 * read tod_version only when the first time and
2061708Sstevel 	 * when there has been a previous sc down time
2071708Sstevel 	 */
2081708Sstevel 	if (!sc_tod_version || is_sc_down >= SC_DOWN_COUNT_THRESHOLD) {
2091708Sstevel 		if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_magic),
210*11752STrevor.Thompson@Sun.COM 		    (char *)&magic, sizeof (uint32_t)) ||
211*11752STrevor.Thompson@Sun.COM 		    magic != TODSG_MAGIC) {
2121708Sstevel 			cmn_err(CE_WARN, "get_sc_tod_version(): "
213*11752STrevor.Thompson@Sun.COM 			    "TOD SRAM magic error");
2141708Sstevel 			return (FALSE);
2151708Sstevel 		}
2161708Sstevel 		if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_version),
217*11752STrevor.Thompson@Sun.COM 		    (char *)&sc_tod_version, sizeof (uint32_t))) {
2181708Sstevel 			cmn_err(CE_WARN, "get_sc_tod_version(): "
219*11752STrevor.Thompson@Sun.COM 			    "read tod version failed");
2201708Sstevel 			sc_tod_version = 0;
2211708Sstevel 			return (FALSE);
2221708Sstevel 		}
2231708Sstevel 	}
2241708Sstevel 	if (sc_tod_version >= SC_TOD_MIN_REV) {
2251708Sstevel 		return (TRUE);
2261708Sstevel 	} else {
2271708Sstevel 		todsg_use_sc = 0;
228*11752STrevor.Thompson@Sun.COM 		cmn_err(CE_WARN, "todsg_get(): incorrect firmware version, "
229*11752STrevor.Thompson@Sun.COM 		    "(%d): expected version >= %d.", sc_tod_version,
230*11752STrevor.Thompson@Sun.COM 		    SC_TOD_MIN_REV);
2311708Sstevel 	}
2321708Sstevel 	return (FALSE);
2331708Sstevel }
2341708Sstevel 
2351708Sstevel static int
update_tod_skew(time_t skew)2361708Sstevel update_tod_skew(time_t skew)
2371708Sstevel {
2381708Sstevel 	time_t domain_skew;
2391708Sstevel 	tod_iosram_t tod_buf;
2401708Sstevel 	int complained = 0;
2411708Sstevel 
2421708Sstevel 	DCMNERR(CE_NOTE, "update_tod_skew(): skew  0x%lX", skew);
2431708Sstevel 
2441708Sstevel 	if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_domain_skew),
245*11752STrevor.Thompson@Sun.COM 	    (char *)&domain_skew, sizeof (time_t))) {
2461708Sstevel 		complained++;
247*11752STrevor.Thompson@Sun.COM 		cmn_err(CE_WARN,
248*11752STrevor.Thompson@Sun.COM 		    "update_tod_skew(): read tod domain skew failed");
2491708Sstevel 	}
2501708Sstevel 	domain_skew += skew;
2511708Sstevel 	/* we shall update the skew_adjust too now */
2521708Sstevel 	domain_skew += skew_adjust;
2531708Sstevel 	if (!complained && iosram_write(SBBC_TOD_KEY,
254*11752STrevor.Thompson@Sun.COM 	    OFFSET(tod_buf, tod_domain_skew), (char *)&domain_skew,
255*11752STrevor.Thompson@Sun.COM 	    sizeof (time_t))) {
2561708Sstevel 		complained++;
257*11752STrevor.Thompson@Sun.COM 		cmn_err(CE_WARN,
258*11752STrevor.Thompson@Sun.COM 		    "update_tod_skew(): write domain skew failed");
2591708Sstevel 	}
2601708Sstevel 	if (!complained)
2611708Sstevel 		skew_adjust = 0;
2621708Sstevel 	return (complained);
2631708Sstevel }
2641708Sstevel 
2651708Sstevel /*
2661708Sstevel  * Return time value read from IOSRAM.
2671708Sstevel  * Must be called with tod_lock held.
2681708Sstevel  */
2691708Sstevel static timestruc_t
todsg_get(void)2701708Sstevel todsg_get(void)
2711708Sstevel {
2721708Sstevel 	tod_iosram_t tod_buf;
2731708Sstevel 	time_t seconds;
2741708Sstevel 	time_t domain_skew;
2751708Sstevel 	int complained = 0;
2761708Sstevel 	static time_t pre_seconds = (time_t)0;
2771708Sstevel 
2781708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
2791708Sstevel 
2801708Sstevel 	if (!verify_sc_tod_version()) {
2811708Sstevel 		/* if we can't use SC */
2821708Sstevel 		goto return_hrestime;
2831708Sstevel 	}
2841708Sstevel 	if (watchdog_activated != 0 || watchdog_enable != 0)
2851708Sstevel 		complained = update_heartbeat();
2861708Sstevel 	if (!complained && (iosram_read(SBBC_TOD_KEY,
287*11752STrevor.Thompson@Sun.COM 	    OFFSET(tod_buf, tod_get_value), (char *)&seconds,
288*11752STrevor.Thompson@Sun.COM 	    sizeof (time_t)))) {
2891708Sstevel 		complained++;
2901708Sstevel 		cmn_err(CE_WARN, "todsg_get(): read 64-bit tod value failed");
2911708Sstevel 	}
2921708Sstevel 	if (!complained && skew_adjust)  {
2931708Sstevel 		/*
2941708Sstevel 		 * This is our first chance to update IOSRAM
2951708Sstevel 		 * with local copy of the skew,  so update it.
2961708Sstevel 		 */
2971708Sstevel 		complained = update_tod_skew(0);
2981708Sstevel 	}
2991708Sstevel 	if (!complained && iosram_read(SBBC_TOD_KEY,
300*11752STrevor.Thompson@Sun.COM 	    OFFSET(tod_buf, tod_domain_skew), (char *)&domain_skew,
301*11752STrevor.Thompson@Sun.COM 	    sizeof (time_t))) {
3021708Sstevel 		complained++;
3031708Sstevel 		cmn_err(CE_WARN, "todsg_get(): read tod domain skew failed");
3041708Sstevel 	}
3051708Sstevel 
3061708Sstevel 	if (complained) {
3071708Sstevel 		cmn_err(CE_WARN, "todsg_get(): turned off using tod");
3081708Sstevel 		todsg_use_sc = 0;
3091708Sstevel 		goto return_hrestime;
3101708Sstevel 	}
3111708Sstevel 
3121708Sstevel 	/*
3131708Sstevel 	 * If the SC gets rebooted, and we are using NTP, then we need
3141708Sstevel 	 * to sync the IOSRAM to hrestime when the SC comes back.  We
3151708Sstevel 	 * can determine that either NTP slew (or date -a) was called if
3161708Sstevel 	 * the global timedelta was non-zero at any point while the SC
3171708Sstevel 	 * was away.  If timedelta remains zero throughout, then the
3181708Sstevel 	 * default action will be to sync hrestime to IOSRAM
3191708Sstevel 	 */
3201708Sstevel 	if (seconds != pre_seconds) {	/* SC still alive */
3211708Sstevel 		pre_seconds = seconds;
3221708Sstevel 		if (is_sc_down >= SC_DOWN_COUNT_THRESHOLD && adjust_sc_down) {
3231708Sstevel 			skew_adjust = hrestime.tv_sec - (seconds + domain_skew);
3241708Sstevel 			complained = update_tod_skew(0);
3251708Sstevel 			if (!complained && (iosram_read(SBBC_TOD_KEY,
326*11752STrevor.Thompson@Sun.COM 			    OFFSET(tod_buf, tod_domain_skew),
327*11752STrevor.Thompson@Sun.COM 			    (char *)&domain_skew, sizeof (time_t)))) {
3281708Sstevel 				complained++;
3291708Sstevel 				cmn_err(CE_WARN, "todsg_get(): "
330*11752STrevor.Thompson@Sun.COM 				    "read tod domain skew failed");
3311708Sstevel 			}
3321708Sstevel 		}
3331708Sstevel 		is_sc_down = 0;
3341708Sstevel 		adjust_sc_down = 0;
3351708Sstevel 
3361708Sstevel 		/*
3371708Sstevel 		 * If complained then domain_skew is invalid.
3381708Sstevel 		 * Hand back hrestime instead.
3391708Sstevel 		 */
3401708Sstevel 		if (!complained) {
341*11752STrevor.Thompson@Sun.COM 			/*
342*11752STrevor.Thompson@Sun.COM 			 * The read was successful so ensure the failure
343*11752STrevor.Thompson@Sun.COM 			 * flag is clear.
344*11752STrevor.Thompson@Sun.COM 			 */
345*11752STrevor.Thompson@Sun.COM 			tod_status_clear(TOD_GET_FAILED);
3461708Sstevel 			timestruc_t ts = {0, 0};
3471708Sstevel 			ts.tv_sec = seconds + domain_skew;
3481708Sstevel 			return (ts);
3491708Sstevel 		} else {
3501708Sstevel 			goto return_hrestime;
3511708Sstevel 		}
3521708Sstevel 	}
3531708Sstevel 
3541708Sstevel 	/* SC/TOD is down */
3551708Sstevel 	is_sc_down++;
3561708Sstevel 	if (timedelta != 0) {
3571708Sstevel 		adjust_sc_down = 1;
3581708Sstevel 	}
3591708Sstevel 
3601708Sstevel return_hrestime:
3611708Sstevel 	/*
362*11752STrevor.Thompson@Sun.COM 	 * We need to inform the tod_validate() code to stop checking until
363*11752STrevor.Thompson@Sun.COM 	 * the SC comes back up again.  Note we will return hrestime below
364*11752STrevor.Thompson@Sun.COM 	 * which may be different to the previous TOD value we returned.
3651708Sstevel 	 */
366*11752STrevor.Thompson@Sun.COM 	tod_status_set(TOD_GET_FAILED);
3671708Sstevel 	return (hrestime);
3681708Sstevel }
3691708Sstevel 
3701708Sstevel static void
todsg_set(timestruc_t ts)3711708Sstevel todsg_set(timestruc_t ts)
3721708Sstevel {
3731708Sstevel 	int complained = 0;
3741708Sstevel 	tod_iosram_t tod_buf;
3751708Sstevel 	time_t domain_skew;
3761708Sstevel 	time_t seconds;
3771708Sstevel 	time_t hwtod;
3781708Sstevel 
3791708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
3801708Sstevel 
3811708Sstevel 	if (!verify_sc_tod_version()) {
3821708Sstevel 		/* if we can't use SC */
3831708Sstevel 		return;
3841708Sstevel 	}
3851708Sstevel 	/*
3861708Sstevel 	 * If the SC is down just note the fact that we should
3871708Sstevel 	 * have adjusted the hardware skew which caters for calls
3881708Sstevel 	 * to stime(). (eg NTP step, as opposed to NTP skew)
3891708Sstevel 	 */
3901708Sstevel 	if (is_sc_down) {
3911708Sstevel 		adjust_sc_down = 1;
3921708Sstevel 		return;
3931708Sstevel 	}
3941708Sstevel 	/*
3951708Sstevel 	 * reason to update i_am_alive here:
3961708Sstevel 	 * To work around a generic Solaris bug that can
3971708Sstevel 	 * cause tod_get() to be starved by too frequent
3981708Sstevel 	 * calls to the stime() system call.
3991708Sstevel 	 */
4001708Sstevel 	if (watchdog_activated != 0 || watchdog_enable != 0)
4011708Sstevel 		complained = update_heartbeat();
4021708Sstevel 
4031708Sstevel 	/*
4041708Sstevel 	 * We are passed hrestime from clock.c so we need to read the
4051708Sstevel 	 * IOSRAM for the hardware's idea of the time to see if we need
4061708Sstevel 	 * to update the skew.
4071708Sstevel 	 */
4081708Sstevel 	if (!complained && (iosram_read(SBBC_TOD_KEY,
409*11752STrevor.Thompson@Sun.COM 	    OFFSET(tod_buf, tod_get_value), (char *)&seconds,
410*11752STrevor.Thompson@Sun.COM 	    sizeof (time_t)))) {
4111708Sstevel 		complained++;
4121708Sstevel 		cmn_err(CE_WARN, "todsg_set(): read 64-bit tod value failed");
4131708Sstevel 	}
4141708Sstevel 
4151708Sstevel 	if (!complained && iosram_read(SBBC_TOD_KEY,
416*11752STrevor.Thompson@Sun.COM 	    OFFSET(tod_buf, tod_domain_skew), (char *)&domain_skew,
417*11752STrevor.Thompson@Sun.COM 	    sizeof (time_t))) {
4181708Sstevel 		complained++;
4191708Sstevel 		cmn_err(CE_WARN, "todsg_set(): read tod domain skew failed");
4201708Sstevel 	}
4211708Sstevel 
4221708Sstevel 	/*
4231708Sstevel 	 * Only update the skew if the time passed differs from
4241708Sstevel 	 * what the hardware thinks & no errors talking to SC
4251708Sstevel 	 */
4261708Sstevel 	if (!complained && (ts.tv_sec != (seconds + domain_skew))) {
4271708Sstevel 		hwtod = seconds + domain_skew;
4281708Sstevel 		complained = update_tod_skew(ts.tv_sec - hwtod);
4291708Sstevel 
4301708Sstevel 		DCMNERR(CE_NOTE, "todsg_set(): set time %lX (%lX)%s",
431*11752STrevor.Thompson@Sun.COM 		    ts.tv_sec, hwtod, complained ? " failed" : "");
4321708Sstevel 	}
4331708Sstevel 
4341708Sstevel 	if (complained) {
4351708Sstevel 		cmn_err(CE_WARN, "todsg_set(): turned off using tod");
4361708Sstevel 		todsg_use_sc = 0;
4371708Sstevel 	}
4381708Sstevel }
4391708Sstevel 
4401708Sstevel static uint32_t
todsg_set_watchdog_timer(uint32_t timeoutval)4411708Sstevel todsg_set_watchdog_timer(uint32_t timeoutval)
4421708Sstevel {
4431708Sstevel 	tod_iosram_t tod_buf;
4441708Sstevel 
4451708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
4461708Sstevel 
4471708Sstevel 	if (!verify_sc_tod_version()) {
4481708Sstevel 		DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
449*11752STrevor.Thompson@Sun.COM 		    "verify_sc_tod_version failed");
4501708Sstevel 		return (0);
4511708Sstevel 	}
4521708Sstevel 	DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
453*11752STrevor.Thompson@Sun.COM 	    "set watchdog timer value = %d", timeoutval);
4541708Sstevel 
4551708Sstevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
456*11752STrevor.Thompson@Sun.COM 	    (char *)&timeoutval, sizeof (uint32_t))) {
4571708Sstevel 		DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
458*11752STrevor.Thompson@Sun.COM 		    "write new timeout value failed");
4591708Sstevel 		return (0);
4601708Sstevel 	}
4611708Sstevel 	watchdog_activated = 1;
4621708Sstevel 	return (timeoutval);
4631708Sstevel }
4641708Sstevel 
4651708Sstevel static uint32_t
todsg_clear_watchdog_timer(void)4661708Sstevel todsg_clear_watchdog_timer(void)
4671708Sstevel {
4681708Sstevel 	tod_iosram_t tod_buf;
4691708Sstevel 	uint32_t r_timeout_period;
4701708Sstevel 	uint32_t w_timeout_period;
4711708Sstevel 
4721708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
4731708Sstevel 
4741708Sstevel 	if ((watchdog_activated == 0) || !verify_sc_tod_version()) {
4751708Sstevel 		DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
476*11752STrevor.Thompson@Sun.COM 		    "either watchdog not activated or "
477*11752STrevor.Thompson@Sun.COM 		    "verify_sc_tod_version failed");
4781708Sstevel 		return (0);
4791708Sstevel 	}
4801708Sstevel 	if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
481*11752STrevor.Thompson@Sun.COM 	    (char *)&r_timeout_period, sizeof (uint32_t))) {
4821708Sstevel 		DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
483*11752STrevor.Thompson@Sun.COM 		    "read timeout value failed");
4841708Sstevel 		return (0);
4851708Sstevel 	}
4861708Sstevel 	DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
487*11752STrevor.Thompson@Sun.COM 	    "clear watchdog timer (old value=%d)", r_timeout_period);
4881708Sstevel 	w_timeout_period = 0;
4891708Sstevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
490*11752STrevor.Thompson@Sun.COM 	    (char *)&w_timeout_period, sizeof (uint32_t))) {
4911708Sstevel 		DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
492*11752STrevor.Thompson@Sun.COM 		    "write zero timeout value failed");
4931708Sstevel 		return (0);
4941708Sstevel 	}
4951708Sstevel 	watchdog_activated = 0;
4961708Sstevel 	return (r_timeout_period);
4971708Sstevel }
4981708Sstevel 
4991708Sstevel /*
5001708Sstevel  * Null function.
5011708Sstevel  */
5021708Sstevel /* ARGSUSED */
5031708Sstevel static void
todsg_set_power_alarm(timestruc_t ts)5041708Sstevel todsg_set_power_alarm(timestruc_t ts)
5051708Sstevel {
5061708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
5071708Sstevel }
5081708Sstevel 
5091708Sstevel /*
5101708Sstevel  * Null function
5111708Sstevel  */
5121708Sstevel static void
todsg_clear_power_alarm()5131708Sstevel todsg_clear_power_alarm()
5141708Sstevel {
5151708Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
5161708Sstevel }
5171708Sstevel 
5181708Sstevel /*
5191708Sstevel  * Get clock freq from the cpunode
5201708Sstevel  */
5211708Sstevel uint64_t
todsg_get_cpufrequency(void)5221708Sstevel todsg_get_cpufrequency(void)
5231708Sstevel {
5241708Sstevel 
5251708Sstevel 	DCMNERR(CE_NOTE, "todsg_get_cpufrequency(): frequency=%ldMHz",
526*11752STrevor.Thompson@Sun.COM 	    cpunodes[CPU->cpu_id].clock_freq/1000000);
5271708Sstevel 
5281708Sstevel 	return (cpunodes[CPU->cpu_id].clock_freq);
5291708Sstevel }
530