1*1c42de6dSgd78059 /* 2*1c42de6dSgd78059 * CDDL HEADER START 3*1c42de6dSgd78059 * 4*1c42de6dSgd78059 * The contents of this file are subject to the terms of the 5*1c42de6dSgd78059 * Common Development and Distribution License (the "License"). 6*1c42de6dSgd78059 * You may not use this file except in compliance with the License. 7*1c42de6dSgd78059 * 8*1c42de6dSgd78059 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1c42de6dSgd78059 * or http://www.opensolaris.org/os/licensing. 10*1c42de6dSgd78059 * See the License for the specific language governing permissions 11*1c42de6dSgd78059 * and limitations under the License. 12*1c42de6dSgd78059 * 13*1c42de6dSgd78059 * When distributing Covered Code, include this CDDL HEADER in each 14*1c42de6dSgd78059 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1c42de6dSgd78059 * If applicable, add the following below this CDDL HEADER, with the 16*1c42de6dSgd78059 * fields enclosed by brackets "[]" replaced with your own identifying 17*1c42de6dSgd78059 * information: Portions Copyright [yyyy] [name of copyright owner] 18*1c42de6dSgd78059 * 19*1c42de6dSgd78059 * CDDL HEADER END 20*1c42de6dSgd78059 */ 21*1c42de6dSgd78059 /* 22*1c42de6dSgd78059 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 23*1c42de6dSgd78059 * Use is subject to license terms. 24*1c42de6dSgd78059 */ 25*1c42de6dSgd78059 26*1c42de6dSgd78059 #pragma ident "%Z%%M% %I% %E% SMI" 27*1c42de6dSgd78059 28*1c42de6dSgd78059 /* 29*1c42de6dSgd78059 * tod driver module for Starcat 30*1c42de6dSgd78059 * This module implements a soft tod since 31*1c42de6dSgd78059 * starcat has no tod part. 32*1c42de6dSgd78059 */ 33*1c42de6dSgd78059 34*1c42de6dSgd78059 #include <sys/types.h> 35*1c42de6dSgd78059 #include <sys/param.h> 36*1c42de6dSgd78059 #include <sys/sysmacros.h> 37*1c42de6dSgd78059 #include <sys/systm.h> 38*1c42de6dSgd78059 #include <sys/errno.h> 39*1c42de6dSgd78059 #include <sys/modctl.h> 40*1c42de6dSgd78059 #include <sys/autoconf.h> 41*1c42de6dSgd78059 #include <sys/debug.h> 42*1c42de6dSgd78059 #include <sys/clock.h> 43*1c42de6dSgd78059 #include <sys/cmn_err.h> 44*1c42de6dSgd78059 #include <sys/promif.h> 45*1c42de6dSgd78059 #include <sys/cpuvar.h> 46*1c42de6dSgd78059 #include <sys/sunddi.h> 47*1c42de6dSgd78059 #include <sys/iosramio.h> 48*1c42de6dSgd78059 #include <sys/domaind.h> 49*1c42de6dSgd78059 50*1c42de6dSgd78059 #define abs(x) ((x) < 0 ? -(x) : (x)) 51*1c42de6dSgd78059 52*1c42de6dSgd78059 #define TODSC_SET_THRESHOLD 30 53*1c42de6dSgd78059 54*1c42de6dSgd78059 static timestruc_t todsc_get(void); 55*1c42de6dSgd78059 static void todsc_set(timestruc_t); 56*1c42de6dSgd78059 static uint_t todsc_set_watchdog_timer(uint_t); 57*1c42de6dSgd78059 static uint_t todsc_clear_watchdog_timer(void); 58*1c42de6dSgd78059 static void todsc_set_power_alarm(timestruc_t); 59*1c42de6dSgd78059 static void todsc_clear_power_alarm(void); 60*1c42de6dSgd78059 static uint64_t todsc_get_cpufrequency(void); 61*1c42de6dSgd78059 62*1c42de6dSgd78059 /* 63*1c42de6dSgd78059 * Module linkage information for the kernel. 64*1c42de6dSgd78059 */ 65*1c42de6dSgd78059 static struct modlmisc modlmisc = { 66*1c42de6dSgd78059 &mod_miscops, "Soft tod module for Sun Fire 15000" 67*1c42de6dSgd78059 }; 68*1c42de6dSgd78059 69*1c42de6dSgd78059 static struct modlinkage modlinkage = { 70*1c42de6dSgd78059 MODREV_1, (void *)&modlmisc, NULL 71*1c42de6dSgd78059 }; 72*1c42de6dSgd78059 73*1c42de6dSgd78059 static uint32_t heartbeat = 0; 74*1c42de6dSgd78059 75*1c42de6dSgd78059 int 76*1c42de6dSgd78059 _init(void) 77*1c42de6dSgd78059 { 78*1c42de6dSgd78059 if (strcmp(tod_module_name, "todstarcat") == 0) { 79*1c42de6dSgd78059 uint32_t ssc_time32 = 0; 80*1c42de6dSgd78059 char obp_string[40]; 81*1c42de6dSgd78059 82*1c42de6dSgd78059 /* 83*1c42de6dSgd78059 * To obtain the initial start of day time, we use an 84*1c42de6dSgd78059 * OBP callback; this is because the iosram is not yet 85*1c42de6dSgd78059 * accessible from the OS at this early stage of startup. 86*1c42de6dSgd78059 */ 87*1c42de6dSgd78059 88*1c42de6dSgd78059 /* 89*1c42de6dSgd78059 * Set the string to pass to OBP 90*1c42de6dSgd78059 * for now, we assume we always get a 32bit value 91*1c42de6dSgd78059 */ 92*1c42de6dSgd78059 (void) sprintf(obp_string, "h# %p unix-gettod", 93*1c42de6dSgd78059 (void *) &ssc_time32); 94*1c42de6dSgd78059 95*1c42de6dSgd78059 prom_interpret(obp_string, 0, 0, 0, 0, 0); 96*1c42de6dSgd78059 97*1c42de6dSgd78059 hrestime.tv_sec = (time_t)ssc_time32; 98*1c42de6dSgd78059 99*1c42de6dSgd78059 /* 100*1c42de6dSgd78059 * A date of zero causes the root filesystem driver 101*1c42de6dSgd78059 * to try to set the date from the last shutdown. 102*1c42de6dSgd78059 */ 103*1c42de6dSgd78059 104*1c42de6dSgd78059 /* 105*1c42de6dSgd78059 * Check for a zero date. 106*1c42de6dSgd78059 */ 107*1c42de6dSgd78059 if (ssc_time32 == 0) { 108*1c42de6dSgd78059 cmn_err(CE_WARN, "Initial date is invalid."); 109*1c42de6dSgd78059 cmn_err(CE_CONT, "Attempting to set the date and time " 110*1c42de6dSgd78059 "based on the last shutdown.\n"); 111*1c42de6dSgd78059 cmn_err(CE_CONT, "Please inspect the date and time and " 112*1c42de6dSgd78059 "correct if necessary.\n"); 113*1c42de6dSgd78059 } 114*1c42de6dSgd78059 115*1c42de6dSgd78059 /* 116*1c42de6dSgd78059 * Check that the date has not overflowed a 32-bit integer. 117*1c42de6dSgd78059 */ 118*1c42de6dSgd78059 if (TIMESPEC_OVERFLOW(&hrestime)) { 119*1c42de6dSgd78059 cmn_err(CE_WARN, "Date overflow detected."); 120*1c42de6dSgd78059 cmn_err(CE_CONT, "Attempting to set the date and time " 121*1c42de6dSgd78059 "based on the last shutdown.\n"); 122*1c42de6dSgd78059 cmn_err(CE_CONT, "Please inspect the date and time and " 123*1c42de6dSgd78059 "correct if necessary.\n"); 124*1c42de6dSgd78059 125*1c42de6dSgd78059 hrestime.tv_sec = (time_t)0; 126*1c42de6dSgd78059 } 127*1c42de6dSgd78059 128*1c42de6dSgd78059 tod_ops.tod_get = todsc_get; 129*1c42de6dSgd78059 tod_ops.tod_set = todsc_set; 130*1c42de6dSgd78059 tod_ops.tod_set_watchdog_timer = todsc_set_watchdog_timer; 131*1c42de6dSgd78059 tod_ops.tod_clear_watchdog_timer = todsc_clear_watchdog_timer; 132*1c42de6dSgd78059 tod_ops.tod_set_power_alarm = todsc_set_power_alarm; 133*1c42de6dSgd78059 tod_ops.tod_clear_power_alarm = todsc_clear_power_alarm; 134*1c42de6dSgd78059 tod_ops.tod_get_cpufrequency = todsc_get_cpufrequency; 135*1c42de6dSgd78059 136*1c42de6dSgd78059 /* 137*1c42de6dSgd78059 * Flag warning if user tried to use hardware watchdog 138*1c42de6dSgd78059 */ 139*1c42de6dSgd78059 if (watchdog_enable) { 140*1c42de6dSgd78059 cmn_err(CE_WARN, "Hardware watchdog unavailable"); 141*1c42de6dSgd78059 } 142*1c42de6dSgd78059 } 143*1c42de6dSgd78059 144*1c42de6dSgd78059 return (mod_install(&modlinkage)); 145*1c42de6dSgd78059 } 146*1c42de6dSgd78059 147*1c42de6dSgd78059 int 148*1c42de6dSgd78059 _fini(void) 149*1c42de6dSgd78059 { 150*1c42de6dSgd78059 if (strcmp(tod_module_name, "todstarcat") == 0) 151*1c42de6dSgd78059 return (EBUSY); 152*1c42de6dSgd78059 else 153*1c42de6dSgd78059 return (mod_remove(&modlinkage)); 154*1c42de6dSgd78059 } 155*1c42de6dSgd78059 156*1c42de6dSgd78059 int 157*1c42de6dSgd78059 _info(struct modinfo *modinfop) 158*1c42de6dSgd78059 { 159*1c42de6dSgd78059 return (mod_info(&modlinkage, modinfop)); 160*1c42de6dSgd78059 } 161*1c42de6dSgd78059 162*1c42de6dSgd78059 163*1c42de6dSgd78059 /* 164*1c42de6dSgd78059 * Starcat tod_get is simplified to return hrestime and to 165*1c42de6dSgd78059 * update the domain heartbeat. 166*1c42de6dSgd78059 * Must be called with tod_lock held. 167*1c42de6dSgd78059 */ 168*1c42de6dSgd78059 static timestruc_t 169*1c42de6dSgd78059 todsc_get(void) 170*1c42de6dSgd78059 { 171*1c42de6dSgd78059 ASSERT(MUTEX_HELD(&tod_lock)); 172*1c42de6dSgd78059 173*1c42de6dSgd78059 heartbeat++; 174*1c42de6dSgd78059 (void) iosram_wr(DOMD_MAGIC, DOMD_HEARTBEAT_OFFSET, 175*1c42de6dSgd78059 sizeof (uint32_t), (caddr_t)&heartbeat); 176*1c42de6dSgd78059 return (hrestime); 177*1c42de6dSgd78059 } 178*1c42de6dSgd78059 179*1c42de6dSgd78059 /* 180*1c42de6dSgd78059 * Must be called with tod_lock held. 181*1c42de6dSgd78059 * 182*1c42de6dSgd78059 * When running NTP, tod_set is called at least once per second in order 183*1c42de6dSgd78059 * to update the hardware clock - for Starcat, we don't want to sync 184*1c42de6dSgd78059 * the non-existent hardware clock, and only want to record significant 185*1c42de6dSgd78059 * time changes on the SC (i.e. when date(1M) is run). So, we have a 186*1c42de6dSgd78059 * threshold requirement before recording the time change. 187*1c42de6dSgd78059 */ 188*1c42de6dSgd78059 /* ARGSUSED */ 189*1c42de6dSgd78059 static void 190*1c42de6dSgd78059 todsc_set(timestruc_t ts) 191*1c42de6dSgd78059 { 192*1c42de6dSgd78059 char obp_string[40]; 193*1c42de6dSgd78059 194*1c42de6dSgd78059 ASSERT(MUTEX_HELD(&tod_lock)); 195*1c42de6dSgd78059 196*1c42de6dSgd78059 heartbeat++; 197*1c42de6dSgd78059 (void) iosram_wr(DOMD_MAGIC, DOMD_HEARTBEAT_OFFSET, 198*1c42de6dSgd78059 sizeof (uint32_t), (caddr_t)&heartbeat); 199*1c42de6dSgd78059 200*1c42de6dSgd78059 if (abs(hrestime.tv_sec - ts.tv_sec) > TODSC_SET_THRESHOLD) { 201*1c42de6dSgd78059 /* 202*1c42de6dSgd78059 * Update the SSC with the new UTC domain time 203*1c42de6dSgd78059 */ 204*1c42de6dSgd78059 (void) sprintf(obp_string, "h# %x unix-settod", 205*1c42de6dSgd78059 (int)ts.tv_sec); 206*1c42de6dSgd78059 207*1c42de6dSgd78059 prom_interpret(obp_string, 0, 0, 0, 0, 0); 208*1c42de6dSgd78059 #ifdef DEBUG 209*1c42de6dSgd78059 cmn_err(CE_NOTE, "todsc_set: new domain time 0x%lx\n", 210*1c42de6dSgd78059 ts.tv_sec); 211*1c42de6dSgd78059 #endif 212*1c42de6dSgd78059 } 213*1c42de6dSgd78059 } 214*1c42de6dSgd78059 215*1c42de6dSgd78059 /* 216*1c42de6dSgd78059 * No watchdog function. 217*1c42de6dSgd78059 */ 218*1c42de6dSgd78059 /* ARGSUSED */ 219*1c42de6dSgd78059 static uint_t 220*1c42de6dSgd78059 todsc_set_watchdog_timer(uint_t timeoutval) 221*1c42de6dSgd78059 { 222*1c42de6dSgd78059 ASSERT(MUTEX_HELD(&tod_lock)); 223*1c42de6dSgd78059 return (0); 224*1c42de6dSgd78059 } 225*1c42de6dSgd78059 226*1c42de6dSgd78059 /* 227*1c42de6dSgd78059 * No watchdog function 228*1c42de6dSgd78059 */ 229*1c42de6dSgd78059 static uint_t 230*1c42de6dSgd78059 todsc_clear_watchdog_timer(void) 231*1c42de6dSgd78059 { 232*1c42de6dSgd78059 ASSERT(MUTEX_HELD(&tod_lock)); 233*1c42de6dSgd78059 return (0); 234*1c42de6dSgd78059 } 235*1c42de6dSgd78059 236*1c42de6dSgd78059 /* 237*1c42de6dSgd78059 * Null function. 238*1c42de6dSgd78059 */ 239*1c42de6dSgd78059 /* ARGSUSED */ 240*1c42de6dSgd78059 static void 241*1c42de6dSgd78059 todsc_set_power_alarm(timestruc_t ts) 242*1c42de6dSgd78059 { 243*1c42de6dSgd78059 ASSERT(MUTEX_HELD(&tod_lock)); 244*1c42de6dSgd78059 } 245*1c42de6dSgd78059 246*1c42de6dSgd78059 /* 247*1c42de6dSgd78059 * Null function 248*1c42de6dSgd78059 */ 249*1c42de6dSgd78059 static void 250*1c42de6dSgd78059 todsc_clear_power_alarm() 251*1c42de6dSgd78059 { 252*1c42de6dSgd78059 ASSERT(MUTEX_HELD(&tod_lock)); 253*1c42de6dSgd78059 } 254*1c42de6dSgd78059 255*1c42de6dSgd78059 /* 256*1c42de6dSgd78059 * Get clock freq from the cpunode. This function is only called 257*1c42de6dSgd78059 * when use_stick = 0, otherwise, system_clock_freq gets used instead. 258*1c42de6dSgd78059 */ 259*1c42de6dSgd78059 uint64_t 260*1c42de6dSgd78059 todsc_get_cpufrequency(void) 261*1c42de6dSgd78059 { 262*1c42de6dSgd78059 return (cpunodes[CPU->cpu_id].clock_freq); 263*1c42de6dSgd78059 } 264