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