1 /* $NetBSD: clock.c,v 1.104 2020/11/22 03:55:33 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1994 Gordon W. Ross 7 * Copyright (c) 1993 Adam Glass 8 * Copyright (c) 1996 Paul Kranenburg 9 * Copyright (c) 1996 10 * The President and Fellows of Harvard College. All rights reserved. 11 * 12 * This software was developed by the Computer Systems Engineering group 13 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 14 * contributed to Berkeley. 15 * 16 * All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Harvard University. 19 * This product includes software developed by the University of 20 * California, Lawrence Berkeley Laboratory. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * This product includes software developed by the University of 34 * California, Berkeley and its contributors. 35 * This product includes software developed by Paul Kranenburg. 36 * This product includes software developed by Harvard University. 37 * 4. Neither the name of the University nor the names of its contributors 38 * may be used to endorse or promote products derived from this software 39 * without specific prior written permission. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * @(#)clock.c 8.1 (Berkeley) 6/11/93 54 * 55 */ 56 57 /* 58 * Common timer, clock and eeprom routines. 59 * 60 * Overview of timer and time-of-day devices on sparc machines: 61 * 62 * sun4/100 & sun4/200 63 * have the Intersil 7170 time-of-day and timer chip (oclock.c) 64 * eeprom device in OBIO space (eeprom.c) 65 * 66 * sun4/300 & sun4/400 67 * Mostek MK48T02 clock/nvram device, includes eeprom (mkclock.c) 68 * 2 system timers (timer.c) 69 * 70 * sun4c 71 * Mostek MK48T02 or MK48T08 clock/nvram device (mkclock.c) 72 * system timer in OBIO space 73 * 2 system timers (timer.c) 74 * 75 * sun4m 76 * Mostek MK48T08 clock/nvram device (mkclock.c) 77 * 1 global system timer (timer.c) 78 * 1 configurable counter/timer per CPU (timer.c) 79 * 80 * microSPARC-IIep: 81 * DS1287A time-of-day chip on EBUS (dev/rtc.c) 82 * the system timer is part of the PCI controller (timer.c) 83 * 84 * All system use the timer interrupt (at IPL 10) to drive hardclock(). 85 * The second or per-CPU timer interrupt (at IPL 14) is used to drive 86 * statclock() (except on sun4/100 and sun4/200 machines, which don't 87 * have a spare timer device). 88 */ 89 90 #include <sys/cdefs.h> 91 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.104 2020/11/22 03:55:33 thorpej Exp $"); 92 93 #include "opt_sparc_arch.h" 94 95 #include <sys/param.h> 96 #include <sys/kernel.h> 97 #include <sys/device.h> 98 #include <sys/proc.h> 99 #include <sys/kmem.h> 100 #include <sys/systm.h> 101 #include <sys/timetc.h> 102 103 #include <sys/bus.h> 104 #include <machine/autoconf.h> 105 #include <machine/eeprom.h> 106 #include <machine/cpu.h> 107 108 #include <dev/clock_subr.h> 109 110 /* Variables shared with timer.c, mkclock.c, oclock.c */ 111 int timerblurb = 10; /* Guess a value; used before clock is attached */ 112 int oldclk = 0; 113 114 void (*timer_init)(void); /* Called from cpu_initclocks() */ 115 int (*eeprom_nvram_wenable)(int); 116 117 /* 118 * Statistics clock interval and variance, in usec. Variance must be a 119 * power of two. Since this gives us an even number, not an odd number, 120 * we discard one case and compensate. That is, a variance of 1024 would 121 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023]. 122 * This is symmetric about the point 512, or statvar/2, and thus averages 123 * to that value (assuming uniform random numbers). 124 */ 125 /* XXX fix comment to match value */ 126 int statvar = 8192; 127 int statmin; /* statclock interval - 1/2*variance */ 128 int statint; 129 130 131 /* 132 * Common eeprom I/O routines. 133 */ 134 char *eeprom_va = NULL; 135 #if defined(SUN4) 136 static int eeprom_busy = 0; 137 static int eeprom_wanted = 0; 138 static int eeprom_take(void); 139 static void eeprom_give(void); 140 static int eeprom_update(char *, int, int); 141 #endif 142 143 /* 144 * Set up the real-time and statistics clocks. 145 * Leave stathz 0 only if no alternative timer is available. 146 * 147 * The frequencies of these clocks must be an even number of microseconds. 148 */ 149 void 150 cpu_initclocks(void) 151 { 152 int minint; 153 154 if (1000000 % hz) { 155 printf("cannot get %d Hz clock; using 100 Hz\n", hz); 156 hz = 100; 157 tick = 1000000 / hz; 158 } 159 if (stathz == 0) 160 stathz = hz; 161 if (1000000 % stathz) { 162 printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); 163 stathz = 100; 164 } 165 profhz = stathz; /* always */ 166 167 statint = 1000000 / stathz; 168 minint = statint / 2 + 100; 169 while (statvar > minint) 170 statvar >>= 1; 171 statmin = statint - (statvar >> 1); 172 173 if (timer_init != NULL) 174 (*timer_init)(); 175 176 /* 177 * The scheduler clock runs every 8 statclock ticks, 178 * assuming stathz == 100. If it's not, compute a mask 179 * for use in the various statintr() functions approx. 180 * like this: 181 * mask = round_power2(stathz / schedhz) - 1 182 */ 183 schedhz = 12; 184 } 185 186 /* 187 * Dummy setstatclockrate(), since we know profhz==hz. 188 */ 189 /* ARGSUSED */ 190 void 191 setstatclockrate(int newhz) 192 { 193 /* nothing */ 194 } 195 196 197 /* 198 * Scheduler pseudo-clock interrupt handler. 199 * Runs off a soft interrupt at IPL_SCHED, scheduled by statintr(). 200 */ 201 void 202 schedintr(void *v) 203 { 204 205 schedclock(curlwp); 206 } 207 208 /* 209 * XXX: these may actually belong somewhere else, but since the 210 * EEPROM is so closely tied to the clock on some models, perhaps 211 * it needs to stay here... 212 */ 213 int 214 eeprom_uio(struct uio *uio) 215 { 216 #if defined(SUN4) 217 int error; 218 int off; /* NOT off_t */ 219 u_int cnt, bcnt; 220 char *buf = NULL; 221 222 if (!CPU_ISSUN4) 223 return (ENODEV); 224 225 if (eeprom_va == NULL) { 226 error = ENXIO; 227 goto out; 228 } 229 230 off = uio->uio_offset; 231 if (off > EEPROM_SIZE) 232 return (EFAULT); 233 234 cnt = uio->uio_resid; 235 if (cnt > (EEPROM_SIZE - off)) 236 cnt = (EEPROM_SIZE - off); 237 238 if ((error = eeprom_take()) != 0) 239 return (error); 240 241 /* 242 * The EEPROM can only be accessed one byte at a time, yet 243 * uiomove() will attempt long-word access. To circumvent 244 * this, we byte-by-byte copy the eeprom contents into a 245 * temporary buffer. 246 */ 247 buf = kmem_alloc(EEPROM_SIZE, KM_SLEEP); 248 249 if (uio->uio_rw == UIO_READ) 250 for (bcnt = 0; bcnt < EEPROM_SIZE; ++bcnt) 251 buf[bcnt] = eeprom_va[bcnt]; 252 253 if ((error = uiomove(buf + off, (int)cnt, uio)) != 0) 254 goto out; 255 256 if (uio->uio_rw != UIO_READ) 257 error = eeprom_update(buf, off, cnt); 258 259 out: 260 kmem_free(buf, EEPROM_SIZE); 261 eeprom_give(); 262 return (error); 263 #else /* ! SUN4 */ 264 return (ENODEV); 265 #endif /* SUN4 */ 266 } 267 268 #if defined(SUN4) 269 /* 270 * Update the EEPROM from the passed buf. 271 */ 272 static int 273 eeprom_update(char *buf, int off, int cnt) 274 { 275 int error = 0; 276 volatile char *ep; 277 char *bp; 278 279 if (eeprom_va == NULL) 280 return (ENXIO); 281 282 ep = eeprom_va + off; 283 bp = buf + off; 284 285 if (eeprom_nvram_wenable != NULL) 286 (*eeprom_nvram_wenable)(1); 287 288 while (cnt > 0) { 289 /* 290 * DO NOT WRITE IT UNLESS WE HAVE TO because the 291 * EEPROM has a limited number of write cycles. 292 * After some number of writes it just fails! 293 */ 294 if (*ep != *bp) { 295 *ep = *bp; 296 /* 297 * We have written the EEPROM, so now we must 298 * sleep for at least 10 milliseconds while 299 * holding the lock to prevent all access to 300 * the EEPROM while it recovers. 301 */ 302 (void)tsleep(eeprom_va, PZERO - 1, "eeprom", hz/50); 303 } 304 /* Make sure the write worked. */ 305 if (*ep != *bp) { 306 error = EIO; 307 goto out; 308 } 309 ++ep; 310 ++bp; 311 --cnt; 312 } 313 out: 314 if (eeprom_nvram_wenable != NULL) 315 (*eeprom_nvram_wenable)(0); 316 317 return (error); 318 } 319 320 /* Take a lock on the eeprom. */ 321 static int 322 eeprom_take(void) 323 { 324 int error = 0; 325 326 while (eeprom_busy) { 327 eeprom_wanted = 1; 328 error = tsleep(&eeprom_busy, PZERO | PCATCH, "eeprom", 0); 329 eeprom_wanted = 0; 330 if (error) /* interrupted */ 331 goto out; 332 } 333 eeprom_busy = 1; 334 out: 335 return (error); 336 } 337 338 /* Give a lock on the eeprom away. */ 339 static void 340 eeprom_give(void) 341 { 342 343 eeprom_busy = 0; 344 if (eeprom_wanted) { 345 eeprom_wanted = 0; 346 wakeup(&eeprom_busy); 347 } 348 } 349 #endif /* SUN4 */ 350