xref: /titanic_50/usr/src/uts/sun4u/io/todsg.c (revision 03831d35f7499c87d51205817c93e9a8d42c4bae)
1*03831d35Sstevel /*
2*03831d35Sstevel  * CDDL HEADER START
3*03831d35Sstevel  *
4*03831d35Sstevel  * The contents of this file are subject to the terms of the
5*03831d35Sstevel  * Common Development and Distribution License, Version 1.0 only
6*03831d35Sstevel  * (the "License").  You may not use this file except in compliance
7*03831d35Sstevel  * with the License.
8*03831d35Sstevel  *
9*03831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*03831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
11*03831d35Sstevel  * See the License for the specific language governing permissions
12*03831d35Sstevel  * and limitations under the License.
13*03831d35Sstevel  *
14*03831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
15*03831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*03831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
17*03831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
18*03831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
19*03831d35Sstevel  *
20*03831d35Sstevel  * CDDL HEADER END
21*03831d35Sstevel  */
22*03831d35Sstevel /*
23*03831d35Sstevel  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*03831d35Sstevel  * Use is subject to license terms.
25*03831d35Sstevel  */
26*03831d35Sstevel 
27*03831d35Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*03831d35Sstevel /*
29*03831d35Sstevel  * tod driver module for Serengeti
30*03831d35Sstevel  * This module implements a soft tod since
31*03831d35Sstevel  * Serengeti has no tod part.
32*03831d35Sstevel  */
33*03831d35Sstevel 
34*03831d35Sstevel #include <sys/modctl.h>
35*03831d35Sstevel #include <sys/systm.h>
36*03831d35Sstevel #include <sys/cpuvar.h>
37*03831d35Sstevel #include <sys/promif.h>
38*03831d35Sstevel #include <sys/sgsbbc_iosram.h>
39*03831d35Sstevel #include <sys/todsg.h>
40*03831d35Sstevel #include <sys/cmn_err.h>
41*03831d35Sstevel #include <sys/time.h>
42*03831d35Sstevel #include <sys/sysmacros.h>
43*03831d35Sstevel #include <sys/clock.h>
44*03831d35Sstevel 
45*03831d35Sstevel #if defined(DEBUG) || defined(lint)
46*03831d35Sstevel static int todsg_debug = 0;
47*03831d35Sstevel #define	DCMNERR if (todsg_debug) cmn_err
48*03831d35Sstevel #else
49*03831d35Sstevel #define	DCMNERR
50*03831d35Sstevel #endif /* DEBUG */
51*03831d35Sstevel 
52*03831d35Sstevel #define	OFFSET(base, field)	((char *)&base.field - (char *)&base)
53*03831d35Sstevel #define	SC_DOWN_COUNT_THRESHOLD	2
54*03831d35Sstevel #define	SC_TOD_MIN_REV		2
55*03831d35Sstevel 
56*03831d35Sstevel static timestruc_t	todsg_get(void);
57*03831d35Sstevel static void		todsg_set(timestruc_t);
58*03831d35Sstevel static uint32_t		todsg_set_watchdog_timer(uint_t);
59*03831d35Sstevel static uint32_t		todsg_clear_watchdog_timer(void);
60*03831d35Sstevel static void		todsg_set_power_alarm(timestruc_t);
61*03831d35Sstevel static void		todsg_clear_power_alarm(void);
62*03831d35Sstevel static uint64_t		todsg_get_cpufrequency(void);
63*03831d35Sstevel static int 		update_heartbeat(void);
64*03831d35Sstevel static int		verify_sc_tod_version(void);
65*03831d35Sstevel static int 		update_tod_skew(time_t skew);
66*03831d35Sstevel 
67*03831d35Sstevel static uint32_t i_am_alive = 0;
68*03831d35Sstevel static uint32_t sc_tod_version = 0;
69*03831d35Sstevel static time_t 	skew_adjust = 0;
70*03831d35Sstevel static int 	is_sc_down = 0;
71*03831d35Sstevel static int	adjust_sc_down = 0;
72*03831d35Sstevel 
73*03831d35Sstevel /*
74*03831d35Sstevel  * Module linkage information for the kernel.
75*03831d35Sstevel  */
76*03831d35Sstevel static struct modlmisc modlmisc = {
77*03831d35Sstevel 	&mod_miscops, "Serengeti tod module v.%I%"
78*03831d35Sstevel };
79*03831d35Sstevel 
80*03831d35Sstevel static struct modlinkage modlinkage = {
81*03831d35Sstevel 	MODREV_1, (void *)&modlmisc, NULL
82*03831d35Sstevel };
83*03831d35Sstevel 
84*03831d35Sstevel int
85*03831d35Sstevel _init(void)
86*03831d35Sstevel {
87*03831d35Sstevel 
88*03831d35Sstevel 	DCMNERR(CE_NOTE, "todsg:_init(): begins");
89*03831d35Sstevel 
90*03831d35Sstevel 	if (strcmp(tod_module_name, "todsg") == 0) {
91*03831d35Sstevel 		time_t ssc_time = (time_t)0;
92*03831d35Sstevel 		char obp_string[80];
93*03831d35Sstevel 
94*03831d35Sstevel 		/*
95*03831d35Sstevel 		 * To obtain the initial start of day time, we use an
96*03831d35Sstevel 		 * OBP callback; this is because the iosram is not yet
97*03831d35Sstevel 		 * accessible from the OS at this early stage of startup.
98*03831d35Sstevel 		 */
99*03831d35Sstevel 
100*03831d35Sstevel 		/*
101*03831d35Sstevel 		 * Set the string to pass to OBP
102*03831d35Sstevel 		 */
103*03831d35Sstevel 		(void) sprintf(obp_string,
104*03831d35Sstevel 			"h# %p \" unix-get-tod\" $find if execute else "
105*03831d35Sstevel 			"3drop then",
106*03831d35Sstevel 			(void *)&ssc_time);
107*03831d35Sstevel 
108*03831d35Sstevel 		prom_interpret(obp_string, 0, 0, 0, 0, 0);
109*03831d35Sstevel 
110*03831d35Sstevel 		if (ssc_time == (time_t)0) {
111*03831d35Sstevel 			cmn_err(CE_WARN, "Initial date is invalid. "
112*03831d35Sstevel 				"This can be caused by older firmware.");
113*03831d35Sstevel 			cmn_err(CE_CONT, "Please flashupdate the System "
114*03831d35Sstevel 				"Controller firmware to the latest version.\n");
115*03831d35Sstevel 			cmn_err(CE_CONT, "Attempting to set the date and time "
116*03831d35Sstevel 				"based on the last shutdown.\n");
117*03831d35Sstevel 			cmn_err(CE_CONT, "Please inspect the date and time and "
118*03831d35Sstevel 				"correct if necessary.\n");
119*03831d35Sstevel 		}
120*03831d35Sstevel 
121*03831d35Sstevel 		hrestime.tv_sec = ssc_time;
122*03831d35Sstevel 
123*03831d35Sstevel 		DCMNERR(CE_NOTE, "todsg: _init(): time from OBP 0x%lX",
124*03831d35Sstevel 				ssc_time);
125*03831d35Sstevel 		/*
126*03831d35Sstevel 		 * Verify whether the received date/clock has overflowed
127*03831d35Sstevel 		 * an integer(32bit), so that we capture any corrupted
128*03831d35Sstevel 		 * date from SC, thereby preventing boot failure.
129*03831d35Sstevel 		 */
130*03831d35Sstevel 		if (TIMESPEC_OVERFLOW(&hrestime)) {
131*03831d35Sstevel 			cmn_err(CE_WARN, "Date overflow detected.");
132*03831d35Sstevel 			cmn_err(CE_CONT, "Attempting to set the date and time "
133*03831d35Sstevel 				"based on the last shutdown.\n");
134*03831d35Sstevel 			cmn_err(CE_CONT, "Please inspect the date and time and "
135*03831d35Sstevel 				"correct if necessary.\n");
136*03831d35Sstevel 
137*03831d35Sstevel 			/*
138*03831d35Sstevel 			 * By setting hrestime.tv_sec to zero
139*03831d35Sstevel 			 * we force the vfs_mountroot() to set
140*03831d35Sstevel 			 * the date from the last shutdown.
141*03831d35Sstevel 			 */
142*03831d35Sstevel 			hrestime.tv_sec = (time_t)0;
143*03831d35Sstevel 			/*
144*03831d35Sstevel 			 * Save the skew so that we can update
145*03831d35Sstevel 			 * IOSRAM when it becomes accessible.
146*03831d35Sstevel 			 */
147*03831d35Sstevel 			skew_adjust = -ssc_time;
148*03831d35Sstevel 		}
149*03831d35Sstevel 
150*03831d35Sstevel 		DCMNERR(CE_NOTE, "todsg:_init(): set tod_ops");
151*03831d35Sstevel 
152*03831d35Sstevel 		tod_ops.tod_get = todsg_get;
153*03831d35Sstevel 		tod_ops.tod_set = todsg_set;
154*03831d35Sstevel 		tod_ops.tod_set_watchdog_timer = todsg_set_watchdog_timer;
155*03831d35Sstevel 		tod_ops.tod_clear_watchdog_timer = todsg_clear_watchdog_timer;
156*03831d35Sstevel 		tod_ops.tod_set_power_alarm = todsg_set_power_alarm;
157*03831d35Sstevel 		tod_ops.tod_clear_power_alarm = todsg_clear_power_alarm;
158*03831d35Sstevel 		tod_ops.tod_get_cpufrequency = todsg_get_cpufrequency;
159*03831d35Sstevel 	}
160*03831d35Sstevel 
161*03831d35Sstevel 	return (mod_install(&modlinkage));
162*03831d35Sstevel 
163*03831d35Sstevel }
164*03831d35Sstevel 
165*03831d35Sstevel int
166*03831d35Sstevel _fini(void)
167*03831d35Sstevel {
168*03831d35Sstevel 	if (strcmp(tod_module_name, "todsg") == 0)
169*03831d35Sstevel 		return (EBUSY);
170*03831d35Sstevel 	else
171*03831d35Sstevel 		return (mod_remove(&modlinkage));
172*03831d35Sstevel }
173*03831d35Sstevel 
174*03831d35Sstevel int
175*03831d35Sstevel _info(struct modinfo *modinfop)
176*03831d35Sstevel {
177*03831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
178*03831d35Sstevel }
179*03831d35Sstevel 
180*03831d35Sstevel static int
181*03831d35Sstevel update_heartbeat(void)
182*03831d35Sstevel {
183*03831d35Sstevel 	tod_iosram_t tod_buf;
184*03831d35Sstevel 	int complained = 0;
185*03831d35Sstevel 
186*03831d35Sstevel 	/* Update the heartbeat */
187*03831d35Sstevel 	if (i_am_alive == UINT32_MAX)
188*03831d35Sstevel 		i_am_alive = 0;
189*03831d35Sstevel 	else
190*03831d35Sstevel 		i_am_alive++;
191*03831d35Sstevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_i_am_alive),
192*03831d35Sstevel 			(char *)&i_am_alive, sizeof (uint32_t))) {
193*03831d35Sstevel 		complained++;
194*03831d35Sstevel 		cmn_err(CE_WARN, "update_heartbeat(): write heartbeat failed");
195*03831d35Sstevel 	}
196*03831d35Sstevel 	return (complained);
197*03831d35Sstevel }
198*03831d35Sstevel 
199*03831d35Sstevel static int
200*03831d35Sstevel verify_sc_tod_version(void)
201*03831d35Sstevel {
202*03831d35Sstevel 	uint32_t magic;
203*03831d35Sstevel 	tod_iosram_t tod_buf;
204*03831d35Sstevel 
205*03831d35Sstevel 	if (!todsg_use_sc)
206*03831d35Sstevel 		return (FALSE);
207*03831d35Sstevel 	/*
208*03831d35Sstevel 	 * read tod_version only when the first time and
209*03831d35Sstevel 	 * when there has been a previous sc down time
210*03831d35Sstevel 	 */
211*03831d35Sstevel 	if (!sc_tod_version || is_sc_down >= SC_DOWN_COUNT_THRESHOLD) {
212*03831d35Sstevel 		if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_magic),
213*03831d35Sstevel 			(char *)&magic, sizeof (uint32_t)) ||
214*03831d35Sstevel 				magic != TODSG_MAGIC) {
215*03831d35Sstevel 			cmn_err(CE_WARN, "get_sc_tod_version(): "
216*03831d35Sstevel 						"TOD SRAM magic error");
217*03831d35Sstevel 			return (FALSE);
218*03831d35Sstevel 		}
219*03831d35Sstevel 		if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_version),
220*03831d35Sstevel 			(char *)&sc_tod_version, sizeof (uint32_t))) {
221*03831d35Sstevel 			cmn_err(CE_WARN, "get_sc_tod_version(): "
222*03831d35Sstevel 				"read tod version failed");
223*03831d35Sstevel 			sc_tod_version = 0;
224*03831d35Sstevel 			return (FALSE);
225*03831d35Sstevel 		}
226*03831d35Sstevel 	}
227*03831d35Sstevel 	if (sc_tod_version >= SC_TOD_MIN_REV) {
228*03831d35Sstevel 		return (TRUE);
229*03831d35Sstevel 	} else {
230*03831d35Sstevel 		todsg_use_sc = 0;
231*03831d35Sstevel 		cmn_err(CE_WARN,
232*03831d35Sstevel 			"todsg_get(): incorrect firmware version, "
233*03831d35Sstevel 			"(%d): expected version >= %d.",
234*03831d35Sstevel 			sc_tod_version, SC_TOD_MIN_REV);
235*03831d35Sstevel 	}
236*03831d35Sstevel 	return (FALSE);
237*03831d35Sstevel }
238*03831d35Sstevel 
239*03831d35Sstevel static int
240*03831d35Sstevel update_tod_skew(time_t skew)
241*03831d35Sstevel {
242*03831d35Sstevel 	time_t domain_skew;
243*03831d35Sstevel 	tod_iosram_t tod_buf;
244*03831d35Sstevel 	int complained = 0;
245*03831d35Sstevel 
246*03831d35Sstevel 	DCMNERR(CE_NOTE, "update_tod_skew(): skew  0x%lX", skew);
247*03831d35Sstevel 
248*03831d35Sstevel 	if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_domain_skew),
249*03831d35Sstevel 			(char *)&domain_skew, sizeof (time_t))) {
250*03831d35Sstevel 		complained++;
251*03831d35Sstevel 		cmn_err(CE_WARN, "update_tod_skew(): "
252*03831d35Sstevel 				"read tod domain skew failed");
253*03831d35Sstevel 	}
254*03831d35Sstevel 	domain_skew += skew;
255*03831d35Sstevel 	/* we shall update the skew_adjust too now */
256*03831d35Sstevel 	domain_skew += skew_adjust;
257*03831d35Sstevel 	if (!complained && iosram_write(SBBC_TOD_KEY,
258*03831d35Sstevel 			OFFSET(tod_buf, tod_domain_skew),
259*03831d35Sstevel 				(char *)&domain_skew, sizeof (time_t))) {
260*03831d35Sstevel 		complained++;
261*03831d35Sstevel 		cmn_err(CE_WARN, "update_tod_skew(): "
262*03831d35Sstevel 				"write domain skew failed");
263*03831d35Sstevel 	}
264*03831d35Sstevel 	if (!complained)
265*03831d35Sstevel 		skew_adjust = 0;
266*03831d35Sstevel 	return (complained);
267*03831d35Sstevel }
268*03831d35Sstevel 
269*03831d35Sstevel 
270*03831d35Sstevel /*
271*03831d35Sstevel  * Return time value read from IOSRAM.
272*03831d35Sstevel  * Must be called with tod_lock held.
273*03831d35Sstevel  */
274*03831d35Sstevel static timestruc_t
275*03831d35Sstevel todsg_get(void)
276*03831d35Sstevel {
277*03831d35Sstevel 	tod_iosram_t tod_buf;
278*03831d35Sstevel 	time_t seconds;
279*03831d35Sstevel 	time_t domain_skew;
280*03831d35Sstevel 	int complained = 0;
281*03831d35Sstevel 	static time_t pre_seconds = (time_t)0;
282*03831d35Sstevel 
283*03831d35Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
284*03831d35Sstevel 
285*03831d35Sstevel 	if (!verify_sc_tod_version()) {
286*03831d35Sstevel 		/* if we can't use SC */
287*03831d35Sstevel 		goto return_hrestime;
288*03831d35Sstevel 	}
289*03831d35Sstevel 	if (watchdog_activated != 0 || watchdog_enable != 0)
290*03831d35Sstevel 		complained = update_heartbeat();
291*03831d35Sstevel 	if (!complained && (iosram_read(SBBC_TOD_KEY,
292*03831d35Sstevel 			OFFSET(tod_buf, tod_get_value),
293*03831d35Sstevel 			(char *)&seconds, sizeof (time_t)))) {
294*03831d35Sstevel 		complained++;
295*03831d35Sstevel 		cmn_err(CE_WARN, "todsg_get(): read 64-bit tod value failed");
296*03831d35Sstevel 	}
297*03831d35Sstevel 	if (!complained && skew_adjust)  {
298*03831d35Sstevel 		/*
299*03831d35Sstevel 		 * This is our first chance to update IOSRAM
300*03831d35Sstevel 		 * with local copy of the skew,  so update it.
301*03831d35Sstevel 		 */
302*03831d35Sstevel 		complained = update_tod_skew(0);
303*03831d35Sstevel 	}
304*03831d35Sstevel 	if (!complained && iosram_read(SBBC_TOD_KEY,
305*03831d35Sstevel 			OFFSET(tod_buf, tod_domain_skew),
306*03831d35Sstevel 			(char *)&domain_skew, sizeof (time_t))) {
307*03831d35Sstevel 		complained++;
308*03831d35Sstevel 		cmn_err(CE_WARN, "todsg_get(): read tod domain skew failed");
309*03831d35Sstevel 	}
310*03831d35Sstevel 
311*03831d35Sstevel 	if (complained) {
312*03831d35Sstevel 		cmn_err(CE_WARN, "todsg_get(): turned off using tod");
313*03831d35Sstevel 		todsg_use_sc = 0;
314*03831d35Sstevel 		goto return_hrestime;
315*03831d35Sstevel 	}
316*03831d35Sstevel 
317*03831d35Sstevel 	/*
318*03831d35Sstevel 	 * If the SC gets rebooted, and we are using NTP, then we need
319*03831d35Sstevel 	 * to sync the IOSRAM to hrestime when the SC comes back.  We
320*03831d35Sstevel 	 * can determine that either NTP slew (or date -a) was called if
321*03831d35Sstevel 	 * the global timedelta was non-zero at any point while the SC
322*03831d35Sstevel 	 * was away.  If timedelta remains zero throughout, then the
323*03831d35Sstevel 	 * default action will be to sync hrestime to IOSRAM
324*03831d35Sstevel 	 */
325*03831d35Sstevel 	if (seconds != pre_seconds) {	/* SC still alive */
326*03831d35Sstevel 		pre_seconds = seconds;
327*03831d35Sstevel 		if (is_sc_down >= SC_DOWN_COUNT_THRESHOLD && adjust_sc_down) {
328*03831d35Sstevel 			skew_adjust = hrestime.tv_sec - (seconds + domain_skew);
329*03831d35Sstevel 			complained = update_tod_skew(0);
330*03831d35Sstevel 			if (!complained && (iosram_read(SBBC_TOD_KEY,
331*03831d35Sstevel 				OFFSET(tod_buf, tod_domain_skew),
332*03831d35Sstevel 				(char *)&domain_skew, sizeof (time_t)))) {
333*03831d35Sstevel 				complained++;
334*03831d35Sstevel 				cmn_err(CE_WARN, "todsg_get(): "
335*03831d35Sstevel 					"read tod domain skew failed");
336*03831d35Sstevel 			}
337*03831d35Sstevel 		}
338*03831d35Sstevel 		is_sc_down = 0;
339*03831d35Sstevel 		adjust_sc_down = 0;
340*03831d35Sstevel 
341*03831d35Sstevel 		/*
342*03831d35Sstevel 		 * If complained then domain_skew is invalid.
343*03831d35Sstevel 		 * Hand back hrestime instead.
344*03831d35Sstevel 		 */
345*03831d35Sstevel 		if (!complained) {
346*03831d35Sstevel 			timestruc_t ts = {0, 0};
347*03831d35Sstevel 			ts.tv_sec = seconds + domain_skew;
348*03831d35Sstevel 			return (ts);
349*03831d35Sstevel 		} else {
350*03831d35Sstevel 			goto return_hrestime;
351*03831d35Sstevel 		}
352*03831d35Sstevel 	}
353*03831d35Sstevel 
354*03831d35Sstevel 	/* SC/TOD is down */
355*03831d35Sstevel 	is_sc_down++;
356*03831d35Sstevel 	if (timedelta != 0) {
357*03831d35Sstevel 		adjust_sc_down = 1;
358*03831d35Sstevel 	}
359*03831d35Sstevel 
360*03831d35Sstevel return_hrestime:
361*03831d35Sstevel 	/*
362*03831d35Sstevel 	 * We need to inform the tod_validate code to stop checking till
363*03831d35Sstevel 	 * SC come back up again. Note that we will return hrestime below
364*03831d35Sstevel 	 * which can be different that the previous TOD value we returned
365*03831d35Sstevel 	 */
366*03831d35Sstevel 	tod_fault_reset();
367*03831d35Sstevel 	return (hrestime);
368*03831d35Sstevel }
369*03831d35Sstevel 
370*03831d35Sstevel static void
371*03831d35Sstevel todsg_set(timestruc_t ts)
372*03831d35Sstevel {
373*03831d35Sstevel 	int complained = 0;
374*03831d35Sstevel 	tod_iosram_t tod_buf;
375*03831d35Sstevel 	time_t domain_skew;
376*03831d35Sstevel 	time_t seconds;
377*03831d35Sstevel 	time_t hwtod;
378*03831d35Sstevel 
379*03831d35Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
380*03831d35Sstevel 
381*03831d35Sstevel 	if (!verify_sc_tod_version()) {
382*03831d35Sstevel 		/* if we can't use SC */
383*03831d35Sstevel 		return;
384*03831d35Sstevel 	}
385*03831d35Sstevel 	/*
386*03831d35Sstevel 	 * If the SC is down just note the fact that we should
387*03831d35Sstevel 	 * have adjusted the hardware skew which caters for calls
388*03831d35Sstevel 	 * to stime(). (eg NTP step, as opposed to NTP skew)
389*03831d35Sstevel 	 */
390*03831d35Sstevel 	if (is_sc_down) {
391*03831d35Sstevel 		adjust_sc_down = 1;
392*03831d35Sstevel 		return;
393*03831d35Sstevel 	}
394*03831d35Sstevel 	/*
395*03831d35Sstevel 	 * reason to update i_am_alive here:
396*03831d35Sstevel 	 * To work around a generic Solaris bug that can
397*03831d35Sstevel 	 * cause tod_get() to be starved by too frequent
398*03831d35Sstevel 	 * calls to the stime() system call.
399*03831d35Sstevel 	 */
400*03831d35Sstevel 	if (watchdog_activated != 0 || watchdog_enable != 0)
401*03831d35Sstevel 		complained = update_heartbeat();
402*03831d35Sstevel 
403*03831d35Sstevel 	/*
404*03831d35Sstevel 	 * We are passed hrestime from clock.c so we need to read the
405*03831d35Sstevel 	 * IOSRAM for the hardware's idea of the time to see if we need
406*03831d35Sstevel 	 * to update the skew.
407*03831d35Sstevel 	 */
408*03831d35Sstevel 	if (!complained && (iosram_read(SBBC_TOD_KEY,
409*03831d35Sstevel 			OFFSET(tod_buf, tod_get_value),
410*03831d35Sstevel 			(char *)&seconds, sizeof (time_t)))) {
411*03831d35Sstevel 		complained++;
412*03831d35Sstevel 		cmn_err(CE_WARN, "todsg_set(): read 64-bit tod value failed");
413*03831d35Sstevel 	}
414*03831d35Sstevel 
415*03831d35Sstevel 	if (!complained && iosram_read(SBBC_TOD_KEY,
416*03831d35Sstevel 			OFFSET(tod_buf, tod_domain_skew),
417*03831d35Sstevel 			(char *)&domain_skew, sizeof (time_t))) {
418*03831d35Sstevel 		complained++;
419*03831d35Sstevel 		cmn_err(CE_WARN, "todsg_set(): read tod domain skew failed");
420*03831d35Sstevel 	}
421*03831d35Sstevel 
422*03831d35Sstevel 	/*
423*03831d35Sstevel 	 * Only update the skew if the time passed differs from
424*03831d35Sstevel 	 * what the hardware thinks & no errors talking to SC
425*03831d35Sstevel 	 */
426*03831d35Sstevel 	if (!complained && (ts.tv_sec != (seconds + domain_skew))) {
427*03831d35Sstevel 		hwtod = seconds + domain_skew;
428*03831d35Sstevel 		complained = update_tod_skew(ts.tv_sec - hwtod);
429*03831d35Sstevel 
430*03831d35Sstevel 		DCMNERR(CE_NOTE, "todsg_set(): set time %lX (%lX)%s",
431*03831d35Sstevel 			ts.tv_sec, hwtod, complained ? " failed" : "");
432*03831d35Sstevel 
433*03831d35Sstevel 	}
434*03831d35Sstevel 
435*03831d35Sstevel 	if (complained) {
436*03831d35Sstevel 		cmn_err(CE_WARN, "todsg_set(): turned off using tod");
437*03831d35Sstevel 		todsg_use_sc = 0;
438*03831d35Sstevel 	}
439*03831d35Sstevel }
440*03831d35Sstevel 
441*03831d35Sstevel static uint32_t
442*03831d35Sstevel todsg_set_watchdog_timer(uint32_t timeoutval)
443*03831d35Sstevel {
444*03831d35Sstevel 	tod_iosram_t tod_buf;
445*03831d35Sstevel 
446*03831d35Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
447*03831d35Sstevel 
448*03831d35Sstevel 	if (!verify_sc_tod_version()) {
449*03831d35Sstevel 		DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
450*03831d35Sstevel 			"verify_sc_tod_version failed");
451*03831d35Sstevel 		return (0);
452*03831d35Sstevel 	}
453*03831d35Sstevel 	DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
454*03831d35Sstevel 		"set watchdog timer value = %d", timeoutval);
455*03831d35Sstevel 
456*03831d35Sstevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
457*03831d35Sstevel 			(char *)&timeoutval, sizeof (uint32_t))) {
458*03831d35Sstevel 		DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
459*03831d35Sstevel 			"write new timeout value failed");
460*03831d35Sstevel 		return (0);
461*03831d35Sstevel 	}
462*03831d35Sstevel 	watchdog_activated = 1;
463*03831d35Sstevel 	return (timeoutval);
464*03831d35Sstevel }
465*03831d35Sstevel 
466*03831d35Sstevel static uint32_t
467*03831d35Sstevel todsg_clear_watchdog_timer(void)
468*03831d35Sstevel {
469*03831d35Sstevel 	tod_iosram_t tod_buf;
470*03831d35Sstevel 	uint32_t r_timeout_period;
471*03831d35Sstevel 	uint32_t w_timeout_period;
472*03831d35Sstevel 
473*03831d35Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
474*03831d35Sstevel 
475*03831d35Sstevel 	if ((watchdog_activated == 0) || !verify_sc_tod_version()) {
476*03831d35Sstevel 		DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
477*03831d35Sstevel 			"either watchdog not activated or "
478*03831d35Sstevel 			"verify_sc_tod_version failed");
479*03831d35Sstevel 		return (0);
480*03831d35Sstevel 	}
481*03831d35Sstevel 	if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
482*03831d35Sstevel 			(char *)&r_timeout_period, sizeof (uint32_t))) {
483*03831d35Sstevel 		DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
484*03831d35Sstevel 			"read timeout value failed");
485*03831d35Sstevel 		return (0);
486*03831d35Sstevel 	}
487*03831d35Sstevel 	DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
488*03831d35Sstevel 		"clear watchdog timer (old value=%d)", r_timeout_period);
489*03831d35Sstevel 	w_timeout_period = 0;
490*03831d35Sstevel 	if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
491*03831d35Sstevel 			(char *)&w_timeout_period, sizeof (uint32_t))) {
492*03831d35Sstevel 		DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
493*03831d35Sstevel 			"write zero timeout value failed");
494*03831d35Sstevel 		return (0);
495*03831d35Sstevel 	}
496*03831d35Sstevel 	watchdog_activated = 0;
497*03831d35Sstevel 	return (r_timeout_period);
498*03831d35Sstevel }
499*03831d35Sstevel 
500*03831d35Sstevel /*
501*03831d35Sstevel  * Null function.
502*03831d35Sstevel  */
503*03831d35Sstevel /* ARGSUSED */
504*03831d35Sstevel static void
505*03831d35Sstevel todsg_set_power_alarm(timestruc_t ts)
506*03831d35Sstevel {
507*03831d35Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
508*03831d35Sstevel }
509*03831d35Sstevel 
510*03831d35Sstevel /*
511*03831d35Sstevel  * Null function
512*03831d35Sstevel  */
513*03831d35Sstevel static void
514*03831d35Sstevel todsg_clear_power_alarm()
515*03831d35Sstevel {
516*03831d35Sstevel 	ASSERT(MUTEX_HELD(&tod_lock));
517*03831d35Sstevel }
518*03831d35Sstevel 
519*03831d35Sstevel /*
520*03831d35Sstevel  * Get clock freq from the cpunode
521*03831d35Sstevel  */
522*03831d35Sstevel uint64_t
523*03831d35Sstevel todsg_get_cpufrequency(void)
524*03831d35Sstevel {
525*03831d35Sstevel 
526*03831d35Sstevel 	DCMNERR(CE_NOTE, "todsg_get_cpufrequency(): frequency=%ldMHz",
527*03831d35Sstevel 		cpunodes[CPU->cpu_id].clock_freq/1000000);
528*03831d35Sstevel 
529*03831d35Sstevel 	return (cpunodes[CPU->cpu_id].clock_freq);
530*03831d35Sstevel }
531