1 /* $NetBSD: clock.c,v 1.17 2002/02/12 20:38:36 scw Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratory. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * @(#)clock.c 8.1 (Berkeley) 6/11/93 45 */ 46 47 #include <sys/param.h> 48 #include <sys/kernel.h> 49 #include <sys/systm.h> 50 #include <sys/device.h> 51 52 #include <machine/psl.h> 53 #include <machine/bus.h> 54 55 #include <dev/mvme/clockvar.h> 56 57 static struct clock_attach_args *clock_args; 58 static todr_chip_handle_t todr_handle; 59 60 struct evcnt clock_profcnt; 61 struct evcnt clock_statcnt; 62 63 /* 64 * Statistics clock interval and variance, in usec. Variance must be a 65 * power of two. Since this gives us an even number, not an odd number, 66 * we discard one case and compensate. That is, a variance of 1024 would 67 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023]. 68 * This is symmetric about the point 512, or statvar/2, and thus averages 69 * to that value (assuming uniform random numbers). 70 */ 71 /* XXX fix comment to match value */ 72 int clock_statvar = 8192; 73 int clock_statmin; /* statclock interval - (1/2 * variance) */ 74 75 76 /* 77 * Common parts of clock autoconfiguration. 78 */ 79 void 80 clock_config(dev, ca, ev) 81 struct device *dev; 82 struct clock_attach_args *ca; 83 struct evcnt *ev; 84 { 85 extern int delay_divisor; /* from machdep.c */ 86 87 /* Hook up that which we need. */ 88 clock_args = ca; 89 90 evcnt_attach_dynamic(&clock_profcnt, EVCNT_TYPE_INTR, ev, 91 dev->dv_xname, "profint"); 92 evcnt_attach_dynamic(&clock_statcnt, EVCNT_TYPE_INTR, ev, 93 dev->dv_xname, "statint"); 94 95 /* Print info about the clock. */ 96 printf(": delay_divisor %d\n", delay_divisor); 97 } 98 99 void 100 clock_rtc_config(todr) 101 todr_chip_handle_t todr; 102 { 103 104 if (todr_handle) 105 panic("clock_config: clock already configured"); 106 107 todr_handle = todr; 108 } 109 110 /* 111 * Set up the real-time and statistics clocks. Leave stathz 0 only 112 * if no alternative timer is available. 113 * 114 * The frequencies of these clocks must be an even number of microseconds. 115 */ 116 void 117 cpu_initclocks() 118 { 119 int statint, minint; 120 121 if (clock_args == NULL) 122 panic("clock not configured"); 123 124 if (1000000 % hz) { 125 printf("cannot get %d Hz clock; using 100 Hz\n", hz); 126 hz = 100; 127 tick = 1000000 / hz; 128 } 129 if (stathz == 0) 130 stathz = hz; 131 if (1000000 % stathz) { 132 printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); 133 stathz = 100; 134 } 135 profhz = stathz; /* always */ 136 137 statint = 1000000 / stathz; 138 minint = statint / 2 + 100; 139 while (clock_statvar > minint) 140 clock_statvar >>= 1; 141 142 clock_statmin = statint - (clock_statvar >> 1); 143 144 /* Call the machine-specific initclocks hook. */ 145 (*clock_args->ca_initfunc)(clock_args->ca_arg, tick, statint); 146 } 147 148 void 149 setstatclockrate(newhz) 150 int newhz; 151 { 152 153 /* XXX should we do something here? XXX */ 154 } 155 156 /* 157 * Return the best possible estimate of the time in the timeval 158 * to which tvp points. We do this by returning the current time 159 * plus the amount of time, in uSec, since the last clock interrupt 160 * (clock_args->ca_microtime()) was handled. 161 * 162 * Check that this time is no less than any previously-reported time, 163 * which could happen around the time of a clock adjustment. Just for fun, 164 * we guarantee that the time will be greater than the value obtained by a 165 * previous call. 166 */ 167 168 void 169 microtime(tvp) 170 struct timeval *tvp; 171 { 172 int s = splhigh(); 173 static struct timeval lasttime; 174 175 *tvp = time; 176 tvp->tv_usec += (*clock_args->ca_microtime)(clock_args->ca_arg); 177 while (tvp->tv_usec >= 1000000) { 178 tvp->tv_sec++; 179 tvp->tv_usec -= 1000000; 180 } 181 if (tvp->tv_sec == lasttime.tv_sec && 182 tvp->tv_usec <= lasttime.tv_usec && 183 (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) { 184 tvp->tv_sec++; 185 tvp->tv_usec -= 1000000; 186 } 187 lasttime = *tvp; 188 splx(s); 189 } 190 191 /* 192 * Set up the system's time, given a `reasonable' time value. 193 */ 194 void 195 inittodr(base) 196 time_t base; 197 { 198 int badbase = 0, waszero = (base == 0); 199 200 if (todr_handle == NULL) 201 panic("todr not configured"); 202 203 if (base < 5 * SECYR) { 204 /* 205 * If base is 0, assume filesystem time is just unknown 206 * in stead of preposterous. Don't bark. 207 */ 208 if (base != 0) 209 printf("WARNING: preposterous time in file system\n"); 210 /* not going to use it anyway, if the chip is readable */ 211 base = 21*SECYR + 186*SECDAY + SECDAY/2; 212 badbase = 1; 213 } 214 215 if (todr_gettime(todr_handle, (struct timeval *)&time) != 0 || 216 time.tv_sec == 0) { 217 printf("WARNING: bad date in battery clock"); 218 /* 219 * Believe the time in the file system for lack of 220 * anything better, resetting the clock. 221 */ 222 time.tv_sec = base; 223 if (!badbase) 224 resettodr(); 225 } else { 226 int deltat = time.tv_sec - base; 227 228 if (deltat < 0) 229 deltat = -deltat; 230 if (waszero || deltat < 2 * SECDAY) 231 return; 232 printf("WARNING: clock %s %d days", 233 time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); 234 } 235 printf(" -- CHECK AND RESET THE DATE!\n"); 236 } 237 238 239 /* 240 * Reset the clock based on the current time. 241 * Used when the current clock is preposterous, when the time is changed, 242 * and when rebooting. Do nothing if the time is not yet known, e.g., 243 * when crashing during autoconfig. 244 */ 245 void 246 resettodr() 247 { 248 249 if (!time.tv_sec) 250 return; 251 252 if (todr_settime(todr_handle, (struct timeval *)&time) != 0) 253 printf("resettodr: failed to set time\n"); 254 } 255