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
cpu_initclocks(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
setstatclockrate(int newhz)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
schedintr(void * v)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
eeprom_uio(struct uio * uio)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
eeprom_update(char * buf,int off,int cnt)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
eeprom_take(void)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
eeprom_give(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