1 /* $NetBSD: clock.c,v 1.7 1995/04/12 15:34:44 ragge Exp $ */ 2 /* 3 * Copyright (c) 1995 Ludd, University of Lule}, Sweden. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed at Ludd, University of Lule}. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* All bugs are subject to removal without further notice */ 33 34 35 36 #include <sys/param.h> 37 #include <sys/kernel.h> 38 39 #include "machine/mtpr.h" 40 #include "machine/sid.h" 41 42 #define SEC_PER_DAY (60*60*24) 43 44 extern int todrstopped; 45 46 static unsigned long year; /* start of current year in seconds */ 47 static unsigned long year_len; /* length of current year in 100th of seconds */ 48 49 /* 50 * microtime() should return number of usecs in struct timeval. 51 * We may get wrap-arounds, but that will be fixed with lasttime 52 * check. This may fault within 10 msecs. 53 */ 54 void 55 microtime(tvp) 56 register struct timeval *tvp; 57 { 58 int s,i; 59 u_int int_time,tmp_year; 60 static struct timeval lasttime; 61 62 s = splhigh(); 63 int_time=mfpr(PR_TODR); 64 bcopy(&time,tvp,sizeof(struct timeval)); 65 i=mfpr(PR_ICR)+tick; /* Get current interval count */ 66 tvp->tv_usec += i; 67 while (tvp->tv_usec > 1000000) { 68 tvp->tv_sec++; 69 tvp->tv_usec -= 1000000; 70 } 71 if (tvp->tv_sec == lasttime.tv_sec && 72 tvp->tv_usec <= lasttime.tv_usec && 73 (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) { 74 tvp->tv_sec++; 75 tvp->tv_usec -= 1000000; 76 } 77 bcopy(tvp,&lasttime,sizeof(struct timeval)); 78 if(int_time>year_len) { 79 mtpr(mfpr(PR_TODR)-year_len, PR_TODR); 80 year+=year_len/100; 81 tmp_year=year/SEC_PER_DAY/365+2; 82 year_len=100*SEC_PER_DAY*((tmp_year%4&&tmp_year!=32)?365:366); 83 } 84 splx(s); 85 } 86 87 /* 88 * Sets year to the year in fs_time and then calculates the number of 89 * 100th of seconds in the current year and saves that info in year_len. 90 * fs_time contains the time set in the superblock in the root filesystem. 91 * If the clock is started, it then checks if the time is valid 92 * compared with the time in fs_time. If the clock is stopped, an 93 * alert is printed and the time is temporary set to the time in fs_time. 94 */ 95 96 void 97 inittodr(fs_time) 98 time_t fs_time; 99 { 100 101 unsigned long tmp_year,sluttid,year_ticks; 102 int clock_stopped; 103 104 sluttid=fs_time; 105 year=(fs_time/SEC_PER_DAY/365)*365*SEC_PER_DAY; 106 tmp_year=year/SEC_PER_DAY/365+2; 107 year_len=100*SEC_PER_DAY*((tmp_year%4&&tmp_year!=32)?365:366); 108 109 switch (cpunumber) { 110 #if VAX750 111 case VAX_750: 112 year_ticks = mfpr(PR_TODR); 113 clock_stopped = todrstopped; 114 break; 115 #endif 116 #if VAX630 || VAX410 117 case VAX_78032: 118 year_ticks = uvaxII_gettodr(&clock_stopped); 119 break; 120 #endif 121 default: 122 year_ticks = 0; 123 clock_stopped = 1; 124 }; 125 126 if(clock_stopped){ 127 printf( 128 "Internal clock not started. Using time from file system.\n"); 129 switch (cpunumber) { 130 #if VAX750 131 case VAX_750: 132 /*+1 so the clock won't be stopped */ 133 mtpr((fs_time-year)*100+1, PR_TODR); 134 break; 135 #endif 136 #if VAX630 || VAX410 137 case VAX_78032: 138 uvaxII_settodr((fs_time-year)*100+1); 139 break; 140 #endif 141 }; 142 todrstopped=0; 143 } else if(year_ticks/100>fs_time-year+SEC_PER_DAY*3) { 144 printf( 145 "WARNING: Clock has gained %d days - CHECK AND RESET THE DATE.\n", 146 (year_ticks/100-(fs_time-year))/SEC_PER_DAY); 147 sluttid=year+(year_ticks/100); 148 } else if(year_ticks/100<fs_time-year) { 149 printf( 150 "WARNING: Clock has lost time - CHECK AND RESET THE DATE.\n"); 151 } else sluttid=year+(year_ticks/100); 152 time.tv_sec=sluttid; 153 } 154 155 /* 156 * Resettodr restores the time of day hardware after a time change. 157 */ 158 159 void 160 resettodr() 161 { 162 163 unsigned long tmp_year; 164 165 year=(time.tv_sec/SEC_PER_DAY/365)*365*SEC_PER_DAY; 166 tmp_year=year/SEC_PER_DAY/365+2; 167 year_len=100*SEC_PER_DAY*((tmp_year%4&&tmp_year!=32)?365:366); 168 switch (cpunumber) { 169 #if VAX750 170 case VAX_750: 171 mtpr((time.tv_sec-year)*100+1, PR_TODR); 172 break; 173 #endif 174 #if VAX630 || VAX410 175 case VAX_78032: 176 uvaxII_settodr((time.tv_sec-year)*100+1); 177 break; 178 #endif 179 }; 180 todrstopped=0; 181 } 182 183 /* 184 * Unfortunately the 78032 cpu chip (MicroVAXII cpu) does not have a functional 185 * todr register, so this function is necessary. 186 * (the x and y variables are used to confuse the optimizer enough to ensure 187 * that the code actually loops:-) 188 */ 189 int 190 todr() 191 { 192 int delaycnt, x = 4, y = 4; 193 static int todr_val; 194 195 if (cpunumber != VAX_78032) 196 return (mfpr(PR_TODR)); 197 198 /* 199 * Loop for approximately 10msec and then return todr_val + 1. 200 */ 201 delaycnt = 5000; 202 while (delaycnt > 0) 203 delaycnt = delaycnt - x + 3 + y - 4; 204 return (++todr_val); 205 } 206