Home | History | Annotate | Line # | Download | only in sparc
      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