1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)clock.c 8.1 (Berkeley) 06/11/93 17 * 18 * from: $Header: clock.c,v 1.17 92/11/26 03:04:47 torek Exp $ (LBL) 19 */ 20 21 /* 22 * Clock driver. This is the id prom (``eeprom'') driver as well 23 * and includes the timer register functions too. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/kernel.h> 28 #include <sys/device.h> 29 #include <sys/proc.h> 30 #include <sys/resourcevar.h> 31 #ifdef GPROF 32 #include <sys/gmon.h> 33 #endif 34 35 #include <vm/vm.h> 36 37 #include <machine/autoconf.h> 38 39 #include <sparc/sparc/clockreg.h> 40 #include <sparc/sparc/intreg.h> 41 #include <sparc/sparc/timerreg.h> 42 43 /* 44 * Statistics clock interval and variance, in usec. Variance must be a 45 * power of two. Since this gives us an even number, not an odd number, 46 * we discard one case and compensate. That is, a variance of 1024 would 47 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023]. 48 * This is symmetric about the point 512, or statvar/2, and thus averages 49 * to that value (assuming uniform random numbers). 50 */ 51 /* XXX fix comment to match value */ 52 int statvar = 8192; 53 int statmin; /* statclock interval - 1/2*variance */ 54 55 static int clockmatch __P((struct device *, struct cfdata *, void *)); 56 static void clockattach __P((struct device *, struct device *, void *)); 57 58 struct cfdriver clockcd = 59 { NULL, "clock", clockmatch, clockattach, DV_DULL, sizeof(struct device) }; 60 61 static int timermatch __P((struct device *, struct cfdata *, void *)); 62 static void timerattach __P((struct device *, struct device *, void *)); 63 struct cfdriver timercd = 64 { NULL, "timer", timermatch, timerattach, DV_DULL, sizeof(struct device) }; 65 66 /* 67 * The OPENPROM calls the clock the "eeprom", so we have to have our 68 * own special match function to call it the "clock". 69 */ 70 static int 71 clockmatch(parent, cf, aux) 72 struct device *parent; 73 struct cfdata *cf; 74 void *aux; 75 { 76 77 return (strcmp("eeprom", ((struct romaux *)aux)->ra_name) == 0); 78 } 79 80 /* ARGSUSED */ 81 static void 82 clockattach(parent, self, aux) 83 struct device *parent, *self; 84 void *aux; 85 { 86 register int h; 87 register struct clockreg *cl; 88 struct romaux *ra = aux; 89 90 printf(": %s (eeprom)\n", getpropstring(ra->ra_node, "model")); 91 /* 92 * We ignore any existing virtual address as we need to map 93 * this read-only and make it read-write only temporarily, 94 * whenever we read or write the clock chip. The clock also 95 * contains the ID ``PROM'', and I have already had the pleasure 96 * of reloading the cpu type, Ethernet address, etc, by hand from 97 * the console FORTH interpreter. I intend not to enjoy it again. 98 */ 99 cl = (struct clockreg *)mapiodev(ra->ra_paddr, sizeof *clockreg); 100 pmap_changeprot(kernel_pmap, (vm_offset_t)clockreg, VM_PROT_READ, 1); 101 h = cl->cl_idprom.id_machine << 24; 102 h |= cl->cl_idprom.id_hostid[0] << 16; 103 h |= cl->cl_idprom.id_hostid[1] << 8; 104 h |= cl->cl_idprom.id_hostid[0]; 105 hostid = h; 106 clockreg = cl; 107 } 108 109 /* 110 * The OPENPROM calls the timer the "counter-timer". 111 */ 112 static int 113 timermatch(parent, cf, aux) 114 struct device *parent; 115 struct cfdata *cf; 116 void *aux; 117 { 118 119 return (strcmp("counter-timer", ((struct romaux *)aux)->ra_name) == 0); 120 } 121 122 /* ARGSUSED */ 123 static void 124 timerattach(parent, self, aux) 125 struct device *parent, *self; 126 void *aux; 127 { 128 register struct romaux *ra = aux; 129 130 printf("\n"); 131 /* 132 * This time, we ignore any existing virtual address because 133 * we have a fixed virtual address for the timer, to make 134 * microtime() faster. 135 */ 136 (void)mapdev(ra->ra_paddr, TIMERREG_VA, sizeof(struct timerreg)); 137 /* should link interrupt handlers here, rather than compiled-in? */ 138 } 139 140 /* 141 * Write en/dis-able clock registers. We coordinate so that several 142 * writers can run simultaneously. 143 */ 144 void 145 clk_wenable(onoff) 146 int onoff; 147 { 148 register int s; 149 register vm_prot_t prot;/* nonzero => change prot */ 150 static int writers; 151 152 s = splhigh(); 153 if (onoff) 154 prot = writers++ == 0 ? VM_PROT_READ|VM_PROT_WRITE : 0; 155 else 156 prot = --writers == 0 ? VM_PROT_READ : 0; 157 splx(s); 158 if (prot) 159 pmap_changeprot(kernel_pmap, (vm_offset_t)clockreg, prot, 1); 160 } 161 162 /* 163 * XXX this belongs elsewhere 164 */ 165 void 166 myetheraddr(cp) 167 u_char *cp; 168 { 169 register struct clockreg *cl = clockreg; 170 171 cp[0] = cl->cl_idprom.id_ether[0]; 172 cp[1] = cl->cl_idprom.id_ether[1]; 173 cp[2] = cl->cl_idprom.id_ether[2]; 174 cp[3] = cl->cl_idprom.id_ether[3]; 175 cp[4] = cl->cl_idprom.id_ether[4]; 176 cp[5] = cl->cl_idprom.id_ether[5]; 177 } 178 179 /* 180 * Delay: wait for `about' n microseconds to pass. 181 * This is easy to do on the SparcStation since we have 182 * freerunning microsecond timers -- no need to guess at 183 * cpu speed factors. We just wait for it to change n times 184 * (if we calculated a limit, we might overshoot, and precision 185 * is irrelevant here---we want less object code). 186 */ 187 delay(n) 188 register int n; 189 { 190 register int c, t; 191 192 if (timercd.cd_ndevs == 0) 193 panic("delay"); 194 c = TIMERREG->t_c10.t_counter; 195 while (--n >= 0) { 196 while ((t = TIMERREG->t_c10.t_counter) == c) 197 continue; 198 c = t; 199 } 200 } 201 202 /* 203 * Set up the real-time and statistics clocks. Leave stathz 0 only if 204 * no alternative timer is available. 205 * 206 * The frequencies of these clocks must be an even number of microseconds. 207 */ 208 cpu_initclocks() 209 { 210 register int statint, minint; 211 212 if (1000000 % hz) { 213 printf("cannot get %d Hz clock; using 100 Hz\n", hz); 214 hz = 100; 215 tick = 1000000 / hz; 216 } 217 if (stathz == 0) 218 stathz = hz; 219 if (1000000 % stathz) { 220 printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); 221 stathz = 100; 222 } 223 profhz = stathz; /* always */ 224 225 statint = 1000000 / stathz; 226 minint = statint / 2 + 100; 227 while (statvar > minint) 228 statvar >>= 1; 229 TIMERREG->t_c10.t_limit = tmr_ustolim(tick); 230 TIMERREG->t_c14.t_limit = tmr_ustolim(statint); 231 statmin = statint - (statvar >> 1); 232 ienab_bis(IE_L14 | IE_L10); 233 } 234 235 /* 236 * Dummy setstatclockrate(), since we know profhz==hz. 237 */ 238 /* ARGSUSED */ 239 void 240 setstatclockrate(newhz) 241 int newhz; 242 { 243 /* nothing */ 244 } 245 246 /* 247 * Level 10 (clock) interrupts. If we are using the FORTH PROM for 248 * console input, we need to check for that here as well, and generate 249 * a software interrupt to read it. 250 */ 251 int 252 clockintr(cap) 253 void *cap; 254 { 255 register int discard; 256 extern int rom_console_input; 257 258 /* read the limit register to clear the interrupt */ 259 discard = TIMERREG->t_c10.t_limit; 260 hardclock((struct clockframe *)cap); 261 if (rom_console_input && cnrom()) 262 setsoftint(); 263 264 return (1); 265 } 266 267 /* 268 * Level 14 (stat clock) interrupt handler. 269 */ 270 int 271 statintr(cap) 272 void *cap; 273 { 274 register int discard; 275 register u_long newint, r, var; 276 277 /* read the limit register to clear the interrupt */ 278 discard = TIMERREG->t_c14.t_limit; 279 statclock((struct clockframe *)cap); 280 281 /* 282 * Compute new randomized interval. The intervals are uniformly 283 * distributed on [statint - statvar / 2, statint + statvar / 2], 284 * and therefore have mean statint, giving a stathz frequency clock. 285 */ 286 var = statvar; 287 do { 288 r = random() & (var - 1); 289 } while (r == 0); 290 newint = statmin + r; 291 292 TIMERREG->t_c14.t_limit = tmr_ustolim(newint); 293 return (1); 294 } 295 296 /* 297 * BCD to decimal and decimal to BCD. 298 */ 299 #define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf)) 300 #define TOBCD(x) (((x) / 10 * 16) + ((x) % 10)) 301 302 #define SECDAY (24 * 60 * 60) 303 #define SECYR (SECDAY * 365) 304 #define LEAPYEAR(y) (((y) & 3) == 0) 305 306 /* 307 * This code is defunct after 2068. 308 * Will Unix still be here then?? 309 */ 310 const short dayyr[12] = 311 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; 312 313 chiptotime(sec, min, hour, day, mon, year) 314 register int sec, min, hour, day, mon, year; 315 { 316 register int days, yr; 317 318 sec = FROMBCD(sec); 319 min = FROMBCD(min); 320 hour = FROMBCD(hour); 321 day = FROMBCD(day); 322 mon = FROMBCD(mon); 323 year = FROMBCD(year) + YEAR0; 324 325 /* simple sanity checks */ 326 if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31) 327 return (0); 328 days = 0; 329 for (yr = 70; yr < year; yr++) 330 days += LEAPYEAR(yr) ? 366 : 365; 331 days += dayyr[mon - 1] + day - 1; 332 if (LEAPYEAR(yr) && mon > 2) 333 days++; 334 /* now have days since Jan 1, 1970; the rest is easy... */ 335 return (days * SECDAY + hour * 3600 + min * 60 + sec); 336 } 337 338 struct chiptime { 339 int sec; 340 int min; 341 int hour; 342 int wday; 343 int day; 344 int mon; 345 int year; 346 }; 347 348 timetochip(c) 349 register struct chiptime *c; 350 { 351 register int t, t2, t3, now = time.tv_sec; 352 353 /* compute the year */ 354 t2 = now / SECDAY; 355 t3 = (t2 + 2) % 7; /* day of week */ 356 c->wday = TOBCD(t3 + 1); 357 358 t = 69; 359 while (t2 >= 0) { /* whittle off years */ 360 t3 = t2; 361 t++; 362 t2 -= LEAPYEAR(t) ? 366 : 365; 363 } 364 c->year = t; 365 366 /* t3 = month + day; separate */ 367 t = LEAPYEAR(t); 368 for (t2 = 1; t2 < 12; t2++) 369 if (t3 < dayyr[t2] + (t && t2 > 1)) 370 break; 371 372 /* t2 is month */ 373 c->mon = t2; 374 c->day = t3 - dayyr[t2 - 1] + 1; 375 if (t && t2 > 2) 376 c->day--; 377 378 /* the rest is easy */ 379 t = now % SECDAY; 380 c->hour = t / 3600; 381 t %= 3600; 382 c->min = t / 60; 383 c->sec = t % 60; 384 385 c->sec = TOBCD(c->sec); 386 c->min = TOBCD(c->min); 387 c->hour = TOBCD(c->hour); 388 c->day = TOBCD(c->day); 389 c->mon = TOBCD(c->mon); 390 c->year = TOBCD(c->year - YEAR0); 391 } 392 393 /* 394 * Set up the system's time, given a `reasonable' time value. 395 */ 396 inittodr(base) 397 time_t base; 398 { 399 register struct clockreg *cl = clockreg; 400 int sec, min, hour, day, mon, year; 401 int badbase = 0; 402 403 if (base < 5 * SECYR) { 404 printf("WARNING: preposterous time in file system\n"); 405 /* not going to use it anyway, if the chip is readable */ 406 base = 21*SECYR + 186*SECDAY + SECDAY/2; 407 badbase = 1; 408 } 409 clk_wenable(1); 410 cl->cl_csr |= CLK_READ; /* enable read (stop time) */ 411 sec = cl->cl_sec; 412 min = cl->cl_min; 413 hour = cl->cl_hour; 414 day = cl->cl_mday; 415 mon = cl->cl_month; 416 year = cl->cl_year; 417 cl->cl_csr &= ~CLK_READ; /* time wears on */ 418 clk_wenable(0); 419 if ((time.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) { 420 printf("WARNING: bad date in battery clock"); 421 /* 422 * Believe the time in the file system for lack of 423 * anything better, resetting the clock. 424 */ 425 time.tv_sec = base; 426 if (!badbase) 427 resettodr(); 428 } else { 429 int deltat = time.tv_sec - base; 430 431 if (deltat < 0) 432 deltat = -deltat; 433 if (deltat < 2 * SECDAY) 434 return; 435 printf("WARNING: clock %s %d days", 436 time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); 437 } 438 printf(" -- CHECK AND RESET THE DATE!\n"); 439 } 440 441 /* 442 * Reset the clock based on the current time. 443 * Used when the current clock is preposterous, when the time is changed, 444 * and when rebooting. Do nothing if the time is not yet known, e.g., 445 * when crashing during autoconfig. 446 */ 447 resettodr() 448 { 449 register struct clockreg *cl; 450 struct chiptime c; 451 452 if (!time.tv_sec || (cl = clockreg) == NULL) 453 return; 454 timetochip(&c); 455 clk_wenable(1); 456 cl->cl_csr |= CLK_WRITE; /* enable write */ 457 cl->cl_sec = c.sec; 458 cl->cl_min = c.min; 459 cl->cl_hour = c.hour; 460 cl->cl_wday = c.wday; 461 cl->cl_mday = c.day; 462 cl->cl_month = c.mon; 463 cl->cl_year = c.year; 464 cl->cl_csr &= ~CLK_WRITE; /* load them up */ 465 clk_wenable(0); 466 } 467