103831d35Sstevel /* 203831d35Sstevel * CDDL HEADER START 303831d35Sstevel * 403831d35Sstevel * The contents of this file are subject to the terms of the 5*88294e09SRichard Bean * Common Development and Distribution License (the "License"). 6*88294e09SRichard 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*88294e09SRichard Bean * Copyright 2008 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 = { 75*88294e09SRichard Bean &mod_miscops, "Serengeti tod module" 7603831d35Sstevel }; 7703831d35Sstevel 7803831d35Sstevel static struct modlinkage modlinkage = { 7903831d35Sstevel MODREV_1, (void *)&modlmisc, NULL 8003831d35Sstevel }; 8103831d35Sstevel 8203831d35Sstevel int 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, 10203831d35Sstevel "h# %p \" unix-get-tod\" $find if execute else " 10303831d35Sstevel "3drop then", 10403831d35Sstevel (void *)&ssc_time); 10503831d35Sstevel 10603831d35Sstevel prom_interpret(obp_string, 0, 0, 0, 0, 0); 10703831d35Sstevel 10803831d35Sstevel if (ssc_time == (time_t)0) { 10903831d35Sstevel cmn_err(CE_WARN, "Initial date is invalid. " 11003831d35Sstevel "This can be caused by older firmware."); 11103831d35Sstevel cmn_err(CE_CONT, "Please flashupdate the System " 11203831d35Sstevel "Controller firmware to the latest version.\n"); 11303831d35Sstevel cmn_err(CE_CONT, "Attempting to set the date and time " 11403831d35Sstevel "based on the last shutdown.\n"); 11503831d35Sstevel cmn_err(CE_CONT, "Please inspect the date and time and " 11603831d35Sstevel "correct if necessary.\n"); 11703831d35Sstevel } 11803831d35Sstevel 11903831d35Sstevel hrestime.tv_sec = ssc_time; 12003831d35Sstevel 12103831d35Sstevel DCMNERR(CE_NOTE, "todsg: _init(): time from OBP 0x%lX", 12203831d35Sstevel ssc_time); 12303831d35Sstevel /* 12403831d35Sstevel * Verify whether the received date/clock has overflowed 12503831d35Sstevel * an integer(32bit), so that we capture any corrupted 12603831d35Sstevel * date from SC, thereby preventing boot failure. 12703831d35Sstevel */ 12803831d35Sstevel if (TIMESPEC_OVERFLOW(&hrestime)) { 12903831d35Sstevel cmn_err(CE_WARN, "Date overflow detected."); 13003831d35Sstevel cmn_err(CE_CONT, "Attempting to set the date and time " 13103831d35Sstevel "based on the last shutdown.\n"); 13203831d35Sstevel cmn_err(CE_CONT, "Please inspect the date and time and " 13303831d35Sstevel "correct if necessary.\n"); 13403831d35Sstevel 13503831d35Sstevel /* 13603831d35Sstevel * By setting hrestime.tv_sec to zero 13703831d35Sstevel * we force the vfs_mountroot() to set 13803831d35Sstevel * the date from the last shutdown. 13903831d35Sstevel */ 14003831d35Sstevel hrestime.tv_sec = (time_t)0; 14103831d35Sstevel /* 14203831d35Sstevel * Save the skew so that we can update 14303831d35Sstevel * IOSRAM when it becomes accessible. 14403831d35Sstevel */ 14503831d35Sstevel skew_adjust = -ssc_time; 14603831d35Sstevel } 14703831d35Sstevel 14803831d35Sstevel DCMNERR(CE_NOTE, "todsg:_init(): set tod_ops"); 14903831d35Sstevel 15003831d35Sstevel tod_ops.tod_get = todsg_get; 15103831d35Sstevel tod_ops.tod_set = todsg_set; 15203831d35Sstevel tod_ops.tod_set_watchdog_timer = todsg_set_watchdog_timer; 15303831d35Sstevel tod_ops.tod_clear_watchdog_timer = todsg_clear_watchdog_timer; 15403831d35Sstevel tod_ops.tod_set_power_alarm = todsg_set_power_alarm; 15503831d35Sstevel tod_ops.tod_clear_power_alarm = todsg_clear_power_alarm; 15603831d35Sstevel tod_ops.tod_get_cpufrequency = todsg_get_cpufrequency; 15703831d35Sstevel } 15803831d35Sstevel 15903831d35Sstevel return (mod_install(&modlinkage)); 16003831d35Sstevel 16103831d35Sstevel } 16203831d35Sstevel 16303831d35Sstevel int 16403831d35Sstevel _fini(void) 16503831d35Sstevel { 16603831d35Sstevel if (strcmp(tod_module_name, "todsg") == 0) 16703831d35Sstevel return (EBUSY); 16803831d35Sstevel else 16903831d35Sstevel return (mod_remove(&modlinkage)); 17003831d35Sstevel } 17103831d35Sstevel 17203831d35Sstevel int 17303831d35Sstevel _info(struct modinfo *modinfop) 17403831d35Sstevel { 17503831d35Sstevel return (mod_info(&modlinkage, modinfop)); 17603831d35Sstevel } 17703831d35Sstevel 17803831d35Sstevel static int 17903831d35Sstevel update_heartbeat(void) 18003831d35Sstevel { 18103831d35Sstevel tod_iosram_t tod_buf; 18203831d35Sstevel int complained = 0; 18303831d35Sstevel 18403831d35Sstevel /* Update the heartbeat */ 18503831d35Sstevel if (i_am_alive == UINT32_MAX) 18603831d35Sstevel i_am_alive = 0; 18703831d35Sstevel else 18803831d35Sstevel i_am_alive++; 18903831d35Sstevel if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_i_am_alive), 19003831d35Sstevel (char *)&i_am_alive, sizeof (uint32_t))) { 19103831d35Sstevel complained++; 19203831d35Sstevel cmn_err(CE_WARN, "update_heartbeat(): write heartbeat failed"); 19303831d35Sstevel } 19403831d35Sstevel return (complained); 19503831d35Sstevel } 19603831d35Sstevel 19703831d35Sstevel static int 19803831d35Sstevel verify_sc_tod_version(void) 19903831d35Sstevel { 20003831d35Sstevel uint32_t magic; 20103831d35Sstevel tod_iosram_t tod_buf; 20203831d35Sstevel 20303831d35Sstevel if (!todsg_use_sc) 20403831d35Sstevel return (FALSE); 20503831d35Sstevel /* 20603831d35Sstevel * read tod_version only when the first time and 20703831d35Sstevel * when there has been a previous sc down time 20803831d35Sstevel */ 20903831d35Sstevel if (!sc_tod_version || is_sc_down >= SC_DOWN_COUNT_THRESHOLD) { 21003831d35Sstevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_magic), 21103831d35Sstevel (char *)&magic, sizeof (uint32_t)) || 21203831d35Sstevel magic != TODSG_MAGIC) { 21303831d35Sstevel cmn_err(CE_WARN, "get_sc_tod_version(): " 21403831d35Sstevel "TOD SRAM magic error"); 21503831d35Sstevel return (FALSE); 21603831d35Sstevel } 21703831d35Sstevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_version), 21803831d35Sstevel (char *)&sc_tod_version, sizeof (uint32_t))) { 21903831d35Sstevel cmn_err(CE_WARN, "get_sc_tod_version(): " 22003831d35Sstevel "read tod version failed"); 22103831d35Sstevel sc_tod_version = 0; 22203831d35Sstevel return (FALSE); 22303831d35Sstevel } 22403831d35Sstevel } 22503831d35Sstevel if (sc_tod_version >= SC_TOD_MIN_REV) { 22603831d35Sstevel return (TRUE); 22703831d35Sstevel } else { 22803831d35Sstevel todsg_use_sc = 0; 22903831d35Sstevel cmn_err(CE_WARN, 23003831d35Sstevel "todsg_get(): incorrect firmware version, " 23103831d35Sstevel "(%d): expected version >= %d.", 23203831d35Sstevel sc_tod_version, SC_TOD_MIN_REV); 23303831d35Sstevel } 23403831d35Sstevel return (FALSE); 23503831d35Sstevel } 23603831d35Sstevel 23703831d35Sstevel static int 23803831d35Sstevel update_tod_skew(time_t skew) 23903831d35Sstevel { 24003831d35Sstevel time_t domain_skew; 24103831d35Sstevel tod_iosram_t tod_buf; 24203831d35Sstevel int complained = 0; 24303831d35Sstevel 24403831d35Sstevel DCMNERR(CE_NOTE, "update_tod_skew(): skew 0x%lX", skew); 24503831d35Sstevel 24603831d35Sstevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_domain_skew), 24703831d35Sstevel (char *)&domain_skew, sizeof (time_t))) { 24803831d35Sstevel complained++; 24903831d35Sstevel cmn_err(CE_WARN, "update_tod_skew(): " 25003831d35Sstevel "read tod domain skew failed"); 25103831d35Sstevel } 25203831d35Sstevel domain_skew += skew; 25303831d35Sstevel /* we shall update the skew_adjust too now */ 25403831d35Sstevel domain_skew += skew_adjust; 25503831d35Sstevel if (!complained && iosram_write(SBBC_TOD_KEY, 25603831d35Sstevel OFFSET(tod_buf, tod_domain_skew), 25703831d35Sstevel (char *)&domain_skew, sizeof (time_t))) { 25803831d35Sstevel complained++; 25903831d35Sstevel cmn_err(CE_WARN, "update_tod_skew(): " 26003831d35Sstevel "write domain skew failed"); 26103831d35Sstevel } 26203831d35Sstevel if (!complained) 26303831d35Sstevel skew_adjust = 0; 26403831d35Sstevel return (complained); 26503831d35Sstevel } 26603831d35Sstevel 26703831d35Sstevel 26803831d35Sstevel /* 26903831d35Sstevel * Return time value read from IOSRAM. 27003831d35Sstevel * Must be called with tod_lock held. 27103831d35Sstevel */ 27203831d35Sstevel static timestruc_t 27303831d35Sstevel todsg_get(void) 27403831d35Sstevel { 27503831d35Sstevel tod_iosram_t tod_buf; 27603831d35Sstevel time_t seconds; 27703831d35Sstevel time_t domain_skew; 27803831d35Sstevel int complained = 0; 27903831d35Sstevel static time_t pre_seconds = (time_t)0; 28003831d35Sstevel 28103831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock)); 28203831d35Sstevel 28303831d35Sstevel if (!verify_sc_tod_version()) { 28403831d35Sstevel /* if we can't use SC */ 28503831d35Sstevel goto return_hrestime; 28603831d35Sstevel } 28703831d35Sstevel if (watchdog_activated != 0 || watchdog_enable != 0) 28803831d35Sstevel complained = update_heartbeat(); 28903831d35Sstevel if (!complained && (iosram_read(SBBC_TOD_KEY, 29003831d35Sstevel OFFSET(tod_buf, tod_get_value), 29103831d35Sstevel (char *)&seconds, sizeof (time_t)))) { 29203831d35Sstevel complained++; 29303831d35Sstevel cmn_err(CE_WARN, "todsg_get(): read 64-bit tod value failed"); 29403831d35Sstevel } 29503831d35Sstevel if (!complained && skew_adjust) { 29603831d35Sstevel /* 29703831d35Sstevel * This is our first chance to update IOSRAM 29803831d35Sstevel * with local copy of the skew, so update it. 29903831d35Sstevel */ 30003831d35Sstevel complained = update_tod_skew(0); 30103831d35Sstevel } 30203831d35Sstevel if (!complained && iosram_read(SBBC_TOD_KEY, 30303831d35Sstevel OFFSET(tod_buf, tod_domain_skew), 30403831d35Sstevel (char *)&domain_skew, sizeof (time_t))) { 30503831d35Sstevel complained++; 30603831d35Sstevel cmn_err(CE_WARN, "todsg_get(): read tod domain skew failed"); 30703831d35Sstevel } 30803831d35Sstevel 30903831d35Sstevel if (complained) { 31003831d35Sstevel cmn_err(CE_WARN, "todsg_get(): turned off using tod"); 31103831d35Sstevel todsg_use_sc = 0; 31203831d35Sstevel goto return_hrestime; 31303831d35Sstevel } 31403831d35Sstevel 31503831d35Sstevel /* 31603831d35Sstevel * If the SC gets rebooted, and we are using NTP, then we need 31703831d35Sstevel * to sync the IOSRAM to hrestime when the SC comes back. We 31803831d35Sstevel * can determine that either NTP slew (or date -a) was called if 31903831d35Sstevel * the global timedelta was non-zero at any point while the SC 32003831d35Sstevel * was away. If timedelta remains zero throughout, then the 32103831d35Sstevel * default action will be to sync hrestime to IOSRAM 32203831d35Sstevel */ 32303831d35Sstevel if (seconds != pre_seconds) { /* SC still alive */ 32403831d35Sstevel pre_seconds = seconds; 32503831d35Sstevel if (is_sc_down >= SC_DOWN_COUNT_THRESHOLD && adjust_sc_down) { 32603831d35Sstevel skew_adjust = hrestime.tv_sec - (seconds + domain_skew); 32703831d35Sstevel complained = update_tod_skew(0); 32803831d35Sstevel if (!complained && (iosram_read(SBBC_TOD_KEY, 32903831d35Sstevel OFFSET(tod_buf, tod_domain_skew), 33003831d35Sstevel (char *)&domain_skew, sizeof (time_t)))) { 33103831d35Sstevel complained++; 33203831d35Sstevel cmn_err(CE_WARN, "todsg_get(): " 33303831d35Sstevel "read tod domain skew failed"); 33403831d35Sstevel } 33503831d35Sstevel } 33603831d35Sstevel is_sc_down = 0; 33703831d35Sstevel adjust_sc_down = 0; 33803831d35Sstevel 33903831d35Sstevel /* 34003831d35Sstevel * If complained then domain_skew is invalid. 34103831d35Sstevel * Hand back hrestime instead. 34203831d35Sstevel */ 34303831d35Sstevel if (!complained) { 34403831d35Sstevel timestruc_t ts = {0, 0}; 34503831d35Sstevel ts.tv_sec = seconds + domain_skew; 34603831d35Sstevel return (ts); 34703831d35Sstevel } else { 34803831d35Sstevel goto return_hrestime; 34903831d35Sstevel } 35003831d35Sstevel } 35103831d35Sstevel 35203831d35Sstevel /* SC/TOD is down */ 35303831d35Sstevel is_sc_down++; 35403831d35Sstevel if (timedelta != 0) { 35503831d35Sstevel adjust_sc_down = 1; 35603831d35Sstevel } 35703831d35Sstevel 35803831d35Sstevel return_hrestime: 35903831d35Sstevel /* 36003831d35Sstevel * We need to inform the tod_validate code to stop checking till 36103831d35Sstevel * SC come back up again. Note that we will return hrestime below 36203831d35Sstevel * which can be different that the previous TOD value we returned 36303831d35Sstevel */ 36403831d35Sstevel tod_fault_reset(); 36503831d35Sstevel return (hrestime); 36603831d35Sstevel } 36703831d35Sstevel 36803831d35Sstevel static void 36903831d35Sstevel todsg_set(timestruc_t ts) 37003831d35Sstevel { 37103831d35Sstevel int complained = 0; 37203831d35Sstevel tod_iosram_t tod_buf; 37303831d35Sstevel time_t domain_skew; 37403831d35Sstevel time_t seconds; 37503831d35Sstevel time_t hwtod; 37603831d35Sstevel 37703831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock)); 37803831d35Sstevel 37903831d35Sstevel if (!verify_sc_tod_version()) { 38003831d35Sstevel /* if we can't use SC */ 38103831d35Sstevel return; 38203831d35Sstevel } 38303831d35Sstevel /* 38403831d35Sstevel * If the SC is down just note the fact that we should 38503831d35Sstevel * have adjusted the hardware skew which caters for calls 38603831d35Sstevel * to stime(). (eg NTP step, as opposed to NTP skew) 38703831d35Sstevel */ 38803831d35Sstevel if (is_sc_down) { 38903831d35Sstevel adjust_sc_down = 1; 39003831d35Sstevel return; 39103831d35Sstevel } 39203831d35Sstevel /* 39303831d35Sstevel * reason to update i_am_alive here: 39403831d35Sstevel * To work around a generic Solaris bug that can 39503831d35Sstevel * cause tod_get() to be starved by too frequent 39603831d35Sstevel * calls to the stime() system call. 39703831d35Sstevel */ 39803831d35Sstevel if (watchdog_activated != 0 || watchdog_enable != 0) 39903831d35Sstevel complained = update_heartbeat(); 40003831d35Sstevel 40103831d35Sstevel /* 40203831d35Sstevel * We are passed hrestime from clock.c so we need to read the 40303831d35Sstevel * IOSRAM for the hardware's idea of the time to see if we need 40403831d35Sstevel * to update the skew. 40503831d35Sstevel */ 40603831d35Sstevel if (!complained && (iosram_read(SBBC_TOD_KEY, 40703831d35Sstevel OFFSET(tod_buf, tod_get_value), 40803831d35Sstevel (char *)&seconds, sizeof (time_t)))) { 40903831d35Sstevel complained++; 41003831d35Sstevel cmn_err(CE_WARN, "todsg_set(): read 64-bit tod value failed"); 41103831d35Sstevel } 41203831d35Sstevel 41303831d35Sstevel if (!complained && iosram_read(SBBC_TOD_KEY, 41403831d35Sstevel OFFSET(tod_buf, tod_domain_skew), 41503831d35Sstevel (char *)&domain_skew, sizeof (time_t))) { 41603831d35Sstevel complained++; 41703831d35Sstevel cmn_err(CE_WARN, "todsg_set(): read tod domain skew failed"); 41803831d35Sstevel } 41903831d35Sstevel 42003831d35Sstevel /* 42103831d35Sstevel * Only update the skew if the time passed differs from 42203831d35Sstevel * what the hardware thinks & no errors talking to SC 42303831d35Sstevel */ 42403831d35Sstevel if (!complained && (ts.tv_sec != (seconds + domain_skew))) { 42503831d35Sstevel hwtod = seconds + domain_skew; 42603831d35Sstevel complained = update_tod_skew(ts.tv_sec - hwtod); 42703831d35Sstevel 42803831d35Sstevel DCMNERR(CE_NOTE, "todsg_set(): set time %lX (%lX)%s", 42903831d35Sstevel ts.tv_sec, hwtod, complained ? " failed" : ""); 43003831d35Sstevel 43103831d35Sstevel } 43203831d35Sstevel 43303831d35Sstevel if (complained) { 43403831d35Sstevel cmn_err(CE_WARN, "todsg_set(): turned off using tod"); 43503831d35Sstevel todsg_use_sc = 0; 43603831d35Sstevel } 43703831d35Sstevel } 43803831d35Sstevel 43903831d35Sstevel static uint32_t 44003831d35Sstevel todsg_set_watchdog_timer(uint32_t timeoutval) 44103831d35Sstevel { 44203831d35Sstevel tod_iosram_t tod_buf; 44303831d35Sstevel 44403831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock)); 44503831d35Sstevel 44603831d35Sstevel if (!verify_sc_tod_version()) { 44703831d35Sstevel DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): " 44803831d35Sstevel "verify_sc_tod_version failed"); 44903831d35Sstevel return (0); 45003831d35Sstevel } 45103831d35Sstevel DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): " 45203831d35Sstevel "set watchdog timer value = %d", timeoutval); 45303831d35Sstevel 45403831d35Sstevel if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period), 45503831d35Sstevel (char *)&timeoutval, sizeof (uint32_t))) { 45603831d35Sstevel DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): " 45703831d35Sstevel "write new timeout value failed"); 45803831d35Sstevel return (0); 45903831d35Sstevel } 46003831d35Sstevel watchdog_activated = 1; 46103831d35Sstevel return (timeoutval); 46203831d35Sstevel } 46303831d35Sstevel 46403831d35Sstevel static uint32_t 46503831d35Sstevel todsg_clear_watchdog_timer(void) 46603831d35Sstevel { 46703831d35Sstevel tod_iosram_t tod_buf; 46803831d35Sstevel uint32_t r_timeout_period; 46903831d35Sstevel uint32_t w_timeout_period; 47003831d35Sstevel 47103831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock)); 47203831d35Sstevel 47303831d35Sstevel if ((watchdog_activated == 0) || !verify_sc_tod_version()) { 47403831d35Sstevel DCMNERR(CE_NOTE, "todsg_set_watchdog_timer(): " 47503831d35Sstevel "either watchdog not activated or " 47603831d35Sstevel "verify_sc_tod_version failed"); 47703831d35Sstevel return (0); 47803831d35Sstevel } 47903831d35Sstevel if (iosram_read(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period), 48003831d35Sstevel (char *)&r_timeout_period, sizeof (uint32_t))) { 48103831d35Sstevel DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): " 48203831d35Sstevel "read timeout value failed"); 48303831d35Sstevel return (0); 48403831d35Sstevel } 48503831d35Sstevel DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): " 48603831d35Sstevel "clear watchdog timer (old value=%d)", r_timeout_period); 48703831d35Sstevel w_timeout_period = 0; 48803831d35Sstevel if (iosram_write(SBBC_TOD_KEY, OFFSET(tod_buf, tod_timeout_period), 48903831d35Sstevel (char *)&w_timeout_period, sizeof (uint32_t))) { 49003831d35Sstevel DCMNERR(CE_NOTE, "todsg_clear_watchdog_timer(): " 49103831d35Sstevel "write zero timeout value failed"); 49203831d35Sstevel return (0); 49303831d35Sstevel } 49403831d35Sstevel watchdog_activated = 0; 49503831d35Sstevel return (r_timeout_period); 49603831d35Sstevel } 49703831d35Sstevel 49803831d35Sstevel /* 49903831d35Sstevel * Null function. 50003831d35Sstevel */ 50103831d35Sstevel /* ARGSUSED */ 50203831d35Sstevel static void 50303831d35Sstevel todsg_set_power_alarm(timestruc_t ts) 50403831d35Sstevel { 50503831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock)); 50603831d35Sstevel } 50703831d35Sstevel 50803831d35Sstevel /* 50903831d35Sstevel * Null function 51003831d35Sstevel */ 51103831d35Sstevel static void 51203831d35Sstevel todsg_clear_power_alarm() 51303831d35Sstevel { 51403831d35Sstevel ASSERT(MUTEX_HELD(&tod_lock)); 51503831d35Sstevel } 51603831d35Sstevel 51703831d35Sstevel /* 51803831d35Sstevel * Get clock freq from the cpunode 51903831d35Sstevel */ 52003831d35Sstevel uint64_t 52103831d35Sstevel todsg_get_cpufrequency(void) 52203831d35Sstevel { 52303831d35Sstevel 52403831d35Sstevel DCMNERR(CE_NOTE, "todsg_get_cpufrequency(): frequency=%ldMHz", 52503831d35Sstevel cpunodes[CPU->cpu_id].clock_freq/1000000); 52603831d35Sstevel 52703831d35Sstevel return (cpunodes[CPU->cpu_id].clock_freq); 52803831d35Sstevel } 529