103831d35Sstevel /*
203831d35Sstevel * CDDL HEADER START
303831d35Sstevel *
403831d35Sstevel * The contents of this file are subject to the terms of the
588294e09SRichard Bean * Common Development and Distribution License (the "License").
688294e09SRichard Bean * You may not use this file except in compliance with the License.
703831d35Sstevel *
803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel * See the License for the specific language governing permissions
1103831d35Sstevel * and limitations under the License.
1203831d35Sstevel *
1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel *
1903831d35Sstevel * CDDL HEADER END
2003831d35Sstevel */
2103831d35Sstevel /*
22*8fc99e42STrevor Thompson * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2303831d35Sstevel * Use is subject to license terms.
2403831d35Sstevel */
2503831d35Sstevel
2603831d35Sstevel /*
2703831d35Sstevel * tod driver module for Serengeti
2803831d35Sstevel * This module implements a soft tod since
2903831d35Sstevel * Serengeti has no tod part.
3003831d35Sstevel */
3103831d35Sstevel
3203831d35Sstevel #include <sys/modctl.h>
3303831d35Sstevel #include <sys/systm.h>
3403831d35Sstevel #include <sys/cpuvar.h>
3503831d35Sstevel #include <sys/promif.h>
3603831d35Sstevel #include <sys/sgsbbc_iosram.h>
3703831d35Sstevel #include <sys/todsg.h>
3803831d35Sstevel #include <sys/cmn_err.h>
3903831d35Sstevel #include <sys/time.h>
4003831d35Sstevel #include <sys/sysmacros.h>
4103831d35Sstevel #include <sys/clock.h>
4203831d35Sstevel
4303831d35Sstevel #if defined(DEBUG) || defined(lint)
4403831d35Sstevel static int todsg_debug = 0;
4503831d35Sstevel #define DCMNERR if (todsg_debug) cmn_err
4603831d35Sstevel #else
4703831d35Sstevel #define DCMNERR
4803831d35Sstevel #endif /* DEBUG */
4903831d35Sstevel
5003831d35Sstevel #define OFFSET(base, field) ((char *)&base.field - (char *)&base)
5103831d35Sstevel #define SC_DOWN_COUNT_THRESHOLD 2
5203831d35Sstevel #define SC_TOD_MIN_REV 2
5303831d35Sstevel
5403831d35Sstevel static timestruc_t todsg_get(void);
5503831d35Sstevel static void todsg_set(timestruc_t);
5603831d35Sstevel static uint32_t todsg_set_watchdog_timer(uint_t);
5703831d35Sstevel static uint32_t todsg_clear_watchdog_timer(void);
5803831d35Sstevel static void todsg_set_power_alarm(timestruc_t);
5903831d35Sstevel static void todsg_clear_power_alarm(void);
6003831d35Sstevel static uint64_t todsg_get_cpufrequency(void);
6103831d35Sstevel static int update_heartbeat(void);
6203831d35Sstevel static int verify_sc_tod_version(void);
6303831d35Sstevel static int update_tod_skew(time_t skew);
6403831d35Sstevel
6503831d35Sstevel static uint32_t i_am_alive = 0;
6603831d35Sstevel static uint32_t sc_tod_version = 0;
6703831d35Sstevel static time_t skew_adjust = 0;
6803831d35Sstevel static int is_sc_down = 0;
6903831d35Sstevel static int adjust_sc_down = 0;
7003831d35Sstevel
7103831d35Sstevel /*
7203831d35Sstevel * Module linkage information for the kernel.
7303831d35Sstevel */
7403831d35Sstevel static struct modlmisc modlmisc = {
7588294e09SRichard Bean &mod_miscops, "Serengeti tod module"
7603831d35Sstevel };
7703831d35Sstevel
7803831d35Sstevel static struct modlinkage modlinkage = {
7903831d35Sstevel MODREV_1, (void *)&modlmisc, NULL
8003831d35Sstevel };
8103831d35Sstevel
8203831d35Sstevel int
_init(void)8303831d35Sstevel _init(void)
8403831d35Sstevel {
8503831d35Sstevel
8603831d35Sstevel DCMNERR(CE_NOTE, "todsg:_init(): begins");
8703831d35Sstevel
8803831d35Sstevel if (strcmp(tod_module_name, "todsg") == 0) {
8903831d35Sstevel time_t ssc_time = (time_t)0;
9003831d35Sstevel char obp_string[80];
9103831d35Sstevel
9203831d35Sstevel /*
9303831d35Sstevel * To obtain the initial start of day time, we use an
9403831d35Sstevel * OBP callback; this is because the iosram is not yet
9503831d35Sstevel * accessible from the OS at this early stage of startup.
9603831d35Sstevel */
9703831d35Sstevel
9803831d35Sstevel /*
9903831d35Sstevel * Set the string to pass to OBP
10003831d35Sstevel */
10103831d35Sstevel (void) sprintf(obp_string,
102*8fc99e42STrevor Thompson "h# %p \" unix-get-tod\" $find if execute else 3drop then",
10303831d35Sstevel (void *)&ssc_time);
10403831d35Sstevel
10503831d35Sstevel prom_interpret(obp_string, 0, 0, 0, 0, 0);
10603831d35Sstevel
10703831d35Sstevel if (ssc_time == (time_t)0) {
10803831d35Sstevel cmn_err(CE_WARN, "Initial date is invalid. "
10903831d35Sstevel "This can be caused by older firmware.");
11003831d35Sstevel cmn_err(CE_CONT, "Please flashupdate the System "
11103831d35Sstevel "Controller firmware to the latest version.\n");
11203831d35Sstevel cmn_err(CE_CONT, "Attempting to set the date and time "
11303831d35Sstevel "based on the last shutdown.\n");
11403831d35Sstevel cmn_err(CE_CONT, "Please inspect the date and time and "
11503831d35Sstevel "correct if necessary.\n");
11603831d35Sstevel }
11703831d35Sstevel
11803831d35Sstevel hrestime.tv_sec = ssc_time;
11903831d35Sstevel
12003831d35Sstevel DCMNERR(CE_NOTE, "todsg: _init(): time from OBP 0x%lX",
12103831d35Sstevel ssc_time);
12203831d35Sstevel /*
12303831d35Sstevel * Verify whether the received date/clock has overflowed
12403831d35Sstevel * an integer(32bit), so that we capture any corrupted
12503831d35Sstevel * date from SC, thereby preventing boot failure.
12603831d35Sstevel */
12703831d35Sstevel if (TIMESPEC_OVERFLOW(&hrestime)) {
12803831d35Sstevel cmn_err(CE_WARN, "Date overflow detected.");
12903831d35Sstevel cmn_err(CE_CONT, "Attempting to set the date and time "
13003831d35Sstevel "based on the last shutdown.\n");
13103831d35Sstevel cmn_err(CE_CONT, "Please inspect the date and time and "
13203831d35Sstevel "correct if necessary.\n");
13303831d35Sstevel
13403831d35Sstevel /*
13503831d35Sstevel * By setting hrestime.tv_sec to zero
13603831d35Sstevel * we force the vfs_mountroot() to set
13703831d35Sstevel * the date from the last shutdown.
13803831d35Sstevel */
13903831d35Sstevel hrestime.tv_sec = (time_t)0;
14003831d35Sstevel /*
14103831d35Sstevel * Save the skew so that we can update
14203831d35Sstevel * IOSRAM when it becomes accessible.
14303831d35Sstevel */
14403831d35Sstevel skew_adjust = -ssc_time;
14503831d35Sstevel }
14603831d35Sstevel
14703831d35Sstevel DCMNERR(CE_NOTE, "todsg:_init(): set tod_ops");
14803831d35Sstevel
14903831d35Sstevel tod_ops.tod_get = todsg_get;
15003831d35Sstevel tod_ops.tod_set = todsg_set;
15103831d35Sstevel tod_ops.tod_set_watchdog_timer = todsg_set_watchdog_timer;
15203831d35Sstevel tod_ops.tod_clear_watchdog_timer = todsg_clear_watchdog_timer;
15303831d35Sstevel tod_ops.tod_set_power_alarm = todsg_set_power_alarm;
15403831d35Sstevel tod_ops.tod_clear_power_alarm = todsg_clear_power_alarm;
15503831d35Sstevel tod_ops.tod_get_cpufrequency = todsg_get_cpufrequency;
15603831d35Sstevel }
15703831d35Sstevel
15803831d35Sstevel return (mod_install(&modlinkage));
15903831d35Sstevel
16003831d35Sstevel }
16103831d35Sstevel
16203831d35Sstevel int
_fini(void)16303831d35Sstevel _fini(void)
16403831d35Sstevel {
16503831d35Sstevel if (strcmp(tod_module_name, "todsg") == 0)
16603831d35Sstevel return (EBUSY);
16703831d35Sstevel else
16803831d35Sstevel return (mod_remove(&modlinkage));
16903831d35Sstevel }
17003831d35Sstevel
17103831d35Sstevel int
_info(struct modinfo * modinfop)17203831d35Sstevel _info(struct modinfo *modinfop)
17303831d35Sstevel {
17403831d35Sstevel return (mod_info(&modlinkage, modinfop));
17503831d35Sstevel }
17603831d35Sstevel
17703831d35Sstevel static int
update_heartbeat(void)17803831d35Sstevel update_heartbeat(void)
17903831d35Sstevel {
18003831d35Sstevel tod_iosram_t tod_buf;
18103831d35Sstevel int complained = 0;
18203831d35Sstevel
18303831d35Sstevel /* Update the heartbeat */
18403831d35Sstevel if (i_am_alive == UINT32_MAX)
18503831d35Sstevel i_am_alive = 0;
18603831d35Sstevel else
18703831d35Sstevel i_am_alive++;
18803831d35Sstevel if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_i_am_alive),
18903831d35Sstevel (char *)&i_am_alive, sizeof (uint32_t))) {
19003831d35Sstevel complained++;
19103831d35Sstevel cmn_err(CE_WARN, "update_heartbeat(): write heartbeat failed");
19203831d35Sstevel }
19303831d35Sstevel return (complained);
19403831d35Sstevel }
19503831d35Sstevel
19603831d35Sstevel static int
verify_sc_tod_version(void)19703831d35Sstevel verify_sc_tod_version(void)
19803831d35Sstevel {
19903831d35Sstevel uint32_t magic;
20003831d35Sstevel tod_iosram_t tod_buf;
20103831d35Sstevel
20203831d35Sstevel if (!todsg_use_sc)
20303831d35Sstevel return (FALSE);
20403831d35Sstevel /*
20503831d35Sstevel * read tod_version only when the first time and
20603831d35Sstevel * when there has been a previous sc down time
20703831d35Sstevel */
20803831d35Sstevel if (!sc_tod_version || is_sc_down >= SC_DOWN_COUNT_THRESHOLD) {
20903831d35Sstevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_magic),
21003831d35Sstevel (char *)&magic, sizeof (uint32_t)) ||
21103831d35Sstevel magic != TODSG_MAGIC) {
21203831d35Sstevel cmn_err(CE_WARN, "get_sc_tod_version(): "
21303831d35Sstevel "TOD SRAM magic error");
21403831d35Sstevel return (FALSE);
21503831d35Sstevel }
21603831d35Sstevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_version),
21703831d35Sstevel (char *)&sc_tod_version, sizeof (uint32_t))) {
21803831d35Sstevel cmn_err(CE_WARN, "get_sc_tod_version(): "
21903831d35Sstevel "read tod version failed");
22003831d35Sstevel sc_tod_version = 0;
22103831d35Sstevel return (FALSE);
22203831d35Sstevel }
22303831d35Sstevel }
22403831d35Sstevel if (sc_tod_version >= SC_TOD_MIN_REV) {
22503831d35Sstevel return (TRUE);
22603831d35Sstevel } else {
22703831d35Sstevel todsg_use_sc = 0;
228*8fc99e42STrevor Thompson cmn_err(CE_WARN, "todsg_get(): incorrect firmware version, "
229*8fc99e42STrevor Thompson "(%d): expected version >= %d.", sc_tod_version,
230*8fc99e42STrevor Thompson SC_TOD_MIN_REV);
23103831d35Sstevel }
23203831d35Sstevel return (FALSE);
23303831d35Sstevel }
23403831d35Sstevel
23503831d35Sstevel static int
update_tod_skew(time_t skew)23603831d35Sstevel update_tod_skew(time_t skew)
23703831d35Sstevel {
23803831d35Sstevel time_t domain_skew;
23903831d35Sstevel tod_iosram_t tod_buf;
24003831d35Sstevel int complained = 0;
24103831d35Sstevel
24203831d35Sstevel DCMNERR(CE_NOTE, "update_tod_skew(): skew 0x%lX", skew);
24303831d35Sstevel
24403831d35Sstevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_domain_skew),
24503831d35Sstevel (char *)&domain_skew, sizeof (time_t))) {
24603831d35Sstevel complained++;
247*8fc99e42STrevor Thompson cmn_err(CE_WARN,
248*8fc99e42STrevor Thompson "update_tod_skew(): read tod domain skew failed");
24903831d35Sstevel }
25003831d35Sstevel domain_skew += skew;
25103831d35Sstevel /* we shall update the skew_adjust too now */
25203831d35Sstevel domain_skew += skew_adjust;
25303831d35Sstevel if (!complained && iosram_write(SBBC_TOD_KEY,
254*8fc99e42STrevor Thompson OFFSET(tod_buf, tod_domain_skew), (char *)&domain_skew,
255*8fc99e42STrevor Thompson sizeof (time_t))) {
25603831d35Sstevel complained++;
257*8fc99e42STrevor Thompson cmn_err(CE_WARN,
258*8fc99e42STrevor Thompson "update_tod_skew(): write domain skew failed");
25903831d35Sstevel }
26003831d35Sstevel if (!complained)
26103831d35Sstevel skew_adjust = 0;
26203831d35Sstevel return (complained);
26303831d35Sstevel }
26403831d35Sstevel
26503831d35Sstevel /*
26603831d35Sstevel * Return time value read from IOSRAM.
26703831d35Sstevel * Must be called with tod_lock held.
26803831d35Sstevel */
26903831d35Sstevel static timestruc_t
todsg_get(void)27003831d35Sstevel todsg_get(void)
27103831d35Sstevel {
27203831d35Sstevel tod_iosram_t tod_buf;
27303831d35Sstevel time_t seconds;
27403831d35Sstevel time_t domain_skew;
27503831d35Sstevel int complained = 0;
27603831d35Sstevel static time_t pre_seconds = (time_t)0;
27703831d35Sstevel
27803831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock));
27903831d35Sstevel
28003831d35Sstevel if (!verify_sc_tod_version()) {
28103831d35Sstevel /* if we can't use SC */
28203831d35Sstevel goto return_hrestime;
28303831d35Sstevel }
28403831d35Sstevel if (watchdog_activated != 0 || watchdog_enable != 0)
28503831d35Sstevel complained = update_heartbeat();
28603831d35Sstevel if (!complained && (iosram_read(SBBC_TOD_KEY,
287*8fc99e42STrevor Thompson OFFSET(tod_buf, tod_get_value), (char *)&seconds,
288*8fc99e42STrevor Thompson sizeof (time_t)))) {
28903831d35Sstevel complained++;
29003831d35Sstevel cmn_err(CE_WARN, "todsg_get(): read 64-bit tod value failed");
29103831d35Sstevel }
29203831d35Sstevel if (!complained && skew_adjust) {
29303831d35Sstevel /*
29403831d35Sstevel * This is our first chance to update IOSRAM
29503831d35Sstevel * with local copy of the skew, so update it.
29603831d35Sstevel */
29703831d35Sstevel complained = update_tod_skew(0);
29803831d35Sstevel }
29903831d35Sstevel if (!complained && iosram_read(SBBC_TOD_KEY,
300*8fc99e42STrevor Thompson OFFSET(tod_buf, tod_domain_skew), (char *)&domain_skew,
301*8fc99e42STrevor Thompson sizeof (time_t))) {
30203831d35Sstevel complained++;
30303831d35Sstevel cmn_err(CE_WARN, "todsg_get(): read tod domain skew failed");
30403831d35Sstevel }
30503831d35Sstevel
30603831d35Sstevel if (complained) {
30703831d35Sstevel cmn_err(CE_WARN, "todsg_get(): turned off using tod");
30803831d35Sstevel todsg_use_sc = 0;
30903831d35Sstevel goto return_hrestime;
31003831d35Sstevel }
31103831d35Sstevel
31203831d35Sstevel /*
31303831d35Sstevel * If the SC gets rebooted, and we are using NTP, then we need
31403831d35Sstevel * to sync the IOSRAM to hrestime when the SC comes back. We
31503831d35Sstevel * can determine that either NTP slew (or date -a) was called if
31603831d35Sstevel * the global timedelta was non-zero at any point while the SC
31703831d35Sstevel * was away. If timedelta remains zero throughout, then the
31803831d35Sstevel * default action will be to sync hrestime to IOSRAM
31903831d35Sstevel */
32003831d35Sstevel if (seconds != pre_seconds) { /* SC still alive */
32103831d35Sstevel pre_seconds = seconds;
32203831d35Sstevel if (is_sc_down >= SC_DOWN_COUNT_THRESHOLD && adjust_sc_down) {
32303831d35Sstevel skew_adjust = hrestime.tv_sec - (seconds + domain_skew);
32403831d35Sstevel complained = update_tod_skew(0);
32503831d35Sstevel if (!complained && (iosram_read(SBBC_TOD_KEY,
32603831d35Sstevel OFFSET(tod_buf, tod_domain_skew),
32703831d35Sstevel (char *)&domain_skew, sizeof (time_t)))) {
32803831d35Sstevel complained++;
32903831d35Sstevel cmn_err(CE_WARN, "todsg_get(): "
33003831d35Sstevel "read tod domain skew failed");
33103831d35Sstevel }
33203831d35Sstevel }
33303831d35Sstevel is_sc_down = 0;
33403831d35Sstevel adjust_sc_down = 0;
33503831d35Sstevel
33603831d35Sstevel /*
33703831d35Sstevel * If complained then domain_skew is invalid.
33803831d35Sstevel * Hand back hrestime instead.
33903831d35Sstevel */
34003831d35Sstevel if (!complained) {
341*8fc99e42STrevor Thompson /*
342*8fc99e42STrevor Thompson * The read was successful so ensure the failure
343*8fc99e42STrevor Thompson * flag is clear.
344*8fc99e42STrevor Thompson */
345*8fc99e42STrevor Thompson tod_status_clear(TOD_GET_FAILED);
34603831d35Sstevel timestruc_t ts = {0, 0};
34703831d35Sstevel ts.tv_sec = seconds + domain_skew;
34803831d35Sstevel return (ts);
34903831d35Sstevel } else {
35003831d35Sstevel goto return_hrestime;
35103831d35Sstevel }
35203831d35Sstevel }
35303831d35Sstevel
35403831d35Sstevel /* SC/TOD is down */
35503831d35Sstevel is_sc_down++;
35603831d35Sstevel if (timedelta != 0) {
35703831d35Sstevel adjust_sc_down = 1;
35803831d35Sstevel }
35903831d35Sstevel
36003831d35Sstevel return_hrestime:
36103831d35Sstevel /*
362*8fc99e42STrevor Thompson * We need to inform the tod_validate() code to stop checking until
363*8fc99e42STrevor Thompson * the SC comes back up again. Note we will return hrestime below
364*8fc99e42STrevor Thompson * which may be different to the previous TOD value we returned.
36503831d35Sstevel */
366*8fc99e42STrevor Thompson tod_status_set(TOD_GET_FAILED);
36703831d35Sstevel return (hrestime);
36803831d35Sstevel }
36903831d35Sstevel
37003831d35Sstevel static void
todsg_set(timestruc_t ts)37103831d35Sstevel todsg_set(timestruc_t ts)
37203831d35Sstevel {
37303831d35Sstevel int complained = 0;
37403831d35Sstevel tod_iosram_t tod_buf;
37503831d35Sstevel time_t domain_skew;
37603831d35Sstevel time_t seconds;
37703831d35Sstevel time_t hwtod;
37803831d35Sstevel
37903831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock));
38003831d35Sstevel
38103831d35Sstevel if (!verify_sc_tod_version()) {
38203831d35Sstevel /* if we can't use SC */
38303831d35Sstevel return;
38403831d35Sstevel }
38503831d35Sstevel /*
38603831d35Sstevel * If the SC is down just note the fact that we should
38703831d35Sstevel * have adjusted the hardware skew which caters for calls
38803831d35Sstevel * to stime(). (eg NTP step, as opposed to NTP skew)
38903831d35Sstevel */
39003831d35Sstevel if (is_sc_down) {
39103831d35Sstevel adjust_sc_down = 1;
39203831d35Sstevel return;
39303831d35Sstevel }
39403831d35Sstevel /*
39503831d35Sstevel * reason to update i_am_alive here:
39603831d35Sstevel * To work around a generic Solaris bug that can
39703831d35Sstevel * cause tod_get() to be starved by too frequent
39803831d35Sstevel * calls to the stime() system call.
39903831d35Sstevel */
40003831d35Sstevel if (watchdog_activated != 0 || watchdog_enable != 0)
40103831d35Sstevel complained = update_heartbeat();
40203831d35Sstevel
40303831d35Sstevel /*
40403831d35Sstevel * We are passed hrestime from clock.c so we need to read the
40503831d35Sstevel * IOSRAM for the hardware's idea of the time to see if we need
40603831d35Sstevel * to update the skew.
40703831d35Sstevel */
40803831d35Sstevel if (!complained && (iosram_read(SBBC_TOD_KEY,
409*8fc99e42STrevor Thompson OFFSET(tod_buf, tod_get_value), (char *)&seconds,
410*8fc99e42STrevor Thompson sizeof (time_t)))) {
41103831d35Sstevel complained++;
41203831d35Sstevel cmn_err(CE_WARN, "todsg_set(): read 64-bit tod value failed");
41303831d35Sstevel }
41403831d35Sstevel
41503831d35Sstevel if (!complained && iosram_read(SBBC_TOD_KEY,
416*8fc99e42STrevor Thompson OFFSET(tod_buf, tod_domain_skew), (char *)&domain_skew,
417*8fc99e42STrevor Thompson sizeof (time_t))) {
41803831d35Sstevel complained++;
41903831d35Sstevel cmn_err(CE_WARN, "todsg_set(): read tod domain skew failed");
42003831d35Sstevel }
42103831d35Sstevel
42203831d35Sstevel /*
42303831d35Sstevel * Only update the skew if the time passed differs from
42403831d35Sstevel * what the hardware thinks & no errors talking to SC
42503831d35Sstevel */
42603831d35Sstevel if (!complained && (ts.tv_sec != (seconds + domain_skew))) {
42703831d35Sstevel hwtod = seconds + domain_skew;
42803831d35Sstevel complained = update_tod_skew(ts.tv_sec - hwtod);
42903831d35Sstevel
43003831d35Sstevel DCMNERR(CE_NOTE, "todsg_set(): set time %lX (%lX)%s",
43103831d35Sstevel ts.tv_sec, hwtod, complained ? " failed" : "");
43203831d35Sstevel }
43303831d35Sstevel
43403831d35Sstevel if (complained) {
43503831d35Sstevel cmn_err(CE_WARN, "todsg_set(): turned off using tod");
43603831d35Sstevel todsg_use_sc = 0;
43703831d35Sstevel }
43803831d35Sstevel }
43903831d35Sstevel
44003831d35Sstevel static uint32_t
todsg_set_watchdog_timer(uint32_t timeoutval)44103831d35Sstevel todsg_set_watchdog_timer(uint32_t timeoutval)
44203831d35Sstevel {
44303831d35Sstevel tod_iosram_t tod_buf;
44403831d35Sstevel
44503831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock));
44603831d35Sstevel
44703831d35Sstevel if (!verify_sc_tod_version()) {
44803831d35Sstevel DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
44903831d35Sstevel "verify_sc_tod_version failed");
45003831d35Sstevel return (0);
45103831d35Sstevel }
45203831d35Sstevel DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
45303831d35Sstevel "set watchdog timer value = %d", timeoutval);
45403831d35Sstevel
45503831d35Sstevel if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
45603831d35Sstevel (char *)&timeoutval, sizeof (uint32_t))) {
45703831d35Sstevel DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
45803831d35Sstevel "write new timeout value failed");
45903831d35Sstevel return (0);
46003831d35Sstevel }
46103831d35Sstevel watchdog_activated = 1;
46203831d35Sstevel return (timeoutval);
46303831d35Sstevel }
46403831d35Sstevel
46503831d35Sstevel static uint32_t
todsg_clear_watchdog_timer(void)46603831d35Sstevel todsg_clear_watchdog_timer(void)
46703831d35Sstevel {
46803831d35Sstevel tod_iosram_t tod_buf;
46903831d35Sstevel uint32_t r_timeout_period;
47003831d35Sstevel uint32_t w_timeout_period;
47103831d35Sstevel
47203831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock));
47303831d35Sstevel
47403831d35Sstevel if ((watchdog_activated == 0) || !verify_sc_tod_version()) {
47503831d35Sstevel DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): "
47603831d35Sstevel "either watchdog not activated or "
47703831d35Sstevel "verify_sc_tod_version failed");
47803831d35Sstevel return (0);
47903831d35Sstevel }
48003831d35Sstevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
48103831d35Sstevel (char *)&r_timeout_period, sizeof (uint32_t))) {
48203831d35Sstevel DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
48303831d35Sstevel "read timeout value failed");
48403831d35Sstevel return (0);
48503831d35Sstevel }
48603831d35Sstevel DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
48703831d35Sstevel "clear watchdog timer (old value=%d)", r_timeout_period);
48803831d35Sstevel w_timeout_period = 0;
48903831d35Sstevel if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period),
49003831d35Sstevel (char *)&w_timeout_period, sizeof (uint32_t))) {
49103831d35Sstevel DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): "
49203831d35Sstevel "write zero timeout value failed");
49303831d35Sstevel return (0);
49403831d35Sstevel }
49503831d35Sstevel watchdog_activated = 0;
49603831d35Sstevel return (r_timeout_period);
49703831d35Sstevel }
49803831d35Sstevel
49903831d35Sstevel /*
50003831d35Sstevel * Null function.
50103831d35Sstevel */
50203831d35Sstevel /* ARGSUSED */
50303831d35Sstevel static void
todsg_set_power_alarm(timestruc_t ts)50403831d35Sstevel todsg_set_power_alarm(timestruc_t ts)
50503831d35Sstevel {
50603831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock));
50703831d35Sstevel }
50803831d35Sstevel
50903831d35Sstevel /*
51003831d35Sstevel * Null function
51103831d35Sstevel */
51203831d35Sstevel static void
todsg_clear_power_alarm()51303831d35Sstevel todsg_clear_power_alarm()
51403831d35Sstevel {
51503831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock));
51603831d35Sstevel }
51703831d35Sstevel
51803831d35Sstevel /*
51903831d35Sstevel * Get clock freq from the cpunode
52003831d35Sstevel */
52103831d35Sstevel uint64_t
todsg_get_cpufrequency(void)52203831d35Sstevel todsg_get_cpufrequency(void)
52303831d35Sstevel {
52403831d35Sstevel
52503831d35Sstevel DCMNERR(CE_NOTE, "todsg_get_cpufrequency(): frequency=%ldMHz",
52603831d35Sstevel cpunodes[CPU->cpu_id].clock_freq/1000000);
52703831d35Sstevel
52803831d35Sstevel return (cpunodes[CPU->cpu_id].clock_freq);
52903831d35Sstevel }
530