1 /* $NetBSD: clock.c,v 1.7 2001/10/11 14:01:36 tsutsui 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 <dev/clock_subr.h> 53 54 #include <news68k/news68k/clockvar.h> 55 56 #include <machine/cpu.h> 57 58 static todr_chip_handle_t todr_handle; 59 static void (*cpu_initclocks_hook) __P((int, int)); 60 61 /* 62 * Common parts of todclock autoconfiguration. 63 */ 64 void 65 todclock_config(handle) 66 todr_chip_handle_t handle; 67 { 68 69 if (todr_handle) 70 panic("todclock_config: too many todclocks configured"); 71 72 todr_handle = handle; 73 } 74 75 void 76 timer_config(initfunc) 77 void (*initfunc)(int, int); 78 { 79 80 if (cpu_initclocks_hook) 81 panic("clock_config: too many timers configured"); 82 83 cpu_initclocks_hook = initfunc; 84 } 85 86 /* 87 * Set up the real-time and statistics clocks. Leave stathz 0 only 88 * if no alternative timer is available. 89 * 90 * The frequencies of these clocks must be an even number of microseconds. 91 */ 92 void 93 cpu_initclocks() 94 { 95 96 if (todr_handle == NULL) 97 panic("no todclock device configured"); 98 99 if (cpu_initclocks_hook == NULL) 100 panic("no timer device configured"); 101 102 if (1000000 % hz) { 103 printf("cannot get %d Hz clock; using 100 Hz\n", hz); 104 hz = 100; 105 tick = 1000000 / hz; 106 } 107 108 /* Call the machine-specific initclocks hook. */ 109 110 (*cpu_initclocks_hook)(0, 0); 111 } 112 113 /* 114 * This does not need to do anything, as we have only one timer and 115 * profhz == stathz == hz. 116 */ 117 void 118 setstatclockrate(newhz) 119 int newhz; 120 { 121 122 /* nothing to do */ 123 } 124 125 /* 126 * Return the best possible estimate of the time in the timeval 127 * to which tvp points. We do this by returning the current time 128 * plus the amount of time since the last clock interrupt (clock.c:clkread). 129 * 130 * Check that this time is no less than any previously-reported time, 131 * which could happen around the time of a clock adjustment. Just for fun, 132 * we guarantee that the time will be greater than the value obtained by a 133 * previous call. 134 */ 135 136 void 137 microtime(tvp) 138 struct timeval *tvp; 139 { 140 int s = splhigh(); 141 static struct timeval lasttime; 142 143 *tvp = time; 144 tvp->tv_usec++; 145 while (tvp->tv_usec >= 1000000) { 146 tvp->tv_sec++; 147 tvp->tv_usec -= 1000000; 148 } 149 if (tvp->tv_sec == lasttime.tv_sec && 150 tvp->tv_usec <= lasttime.tv_usec && 151 (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) { 152 tvp->tv_sec++; 153 tvp->tv_usec -= 1000000; 154 } 155 lasttime = *tvp; 156 splx(s); 157 } 158 159 /* 160 * Set up the system's time, given a `reasonable' time value. 161 */ 162 void 163 inittodr(base) 164 time_t base; 165 { 166 int badbase = 0, waszero = (base == 0); 167 168 if (base < 5 * SECYR) { 169 /* 170 * If base is 0, assume filesystem time is just unknown 171 * in stead of preposterous. Don't bark. 172 */ 173 if (base != 0) 174 printf("WARNING: preposterous time in file system\n"); 175 /* not going to use it anyway, if the chip is readable */ 176 /* 1991/07/01 12:00:00 */ 177 base = 21*SECYR + 186*SECDAY + SECDAY/2; 178 badbase = 1; 179 } 180 181 if (todr_gettime(todr_handle, (struct timeval *)&time) != 0 || 182 time.tv_sec == 0) { 183 printf("WARNING: bad date in battery clock"); 184 /* 185 * Believe the time in the file system for lack of 186 * anything better, resetting the clock. 187 */ 188 time.tv_sec = base; 189 if (!badbase) 190 resettodr(); 191 } else { 192 int deltat = time.tv_sec - base; 193 194 if (deltat < 0) 195 deltat = -deltat; 196 if (waszero || deltat < 2 * SECDAY) 197 return; 198 printf("WARNING: clock %s %d days", 199 time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); 200 } 201 printf(" -- CHECK AND RESET THE DATE!\n"); 202 } 203 204 /* 205 * Reset the clock based on the current time. 206 * Used when the current clock is preposterous, when the time is changed, 207 * and when rebooting. Do nothing if the time is not yet known, e.g., 208 * when crashing during autoconfig. 209 */ 210 void 211 resettodr() 212 { 213 214 if (time.tv_sec == 0) 215 return; 216 217 if (todr_settime(todr_handle, (struct timeval *)&time) != 0) 218 printf("resettodr: cannot set time in time-of-day clock\n"); 219 } 220