Home | History | Annotate | Line # | Download | only in isa
clock.c revision 1.1.2.3
      1  1.1.2.3  nathanw /*	$NetBSD: clock.c,v 1.1.2.3 2002/10/18 02:39:46 nathanw Exp $	*/
      2  1.1.2.2  nathanw 
      3  1.1.2.2  nathanw /*
      4  1.1.2.2  nathanw  * Copyright 1997
      5  1.1.2.2  nathanw  * Digital Equipment Corporation. All rights reserved.
      6  1.1.2.2  nathanw  *
      7  1.1.2.2  nathanw  * This software is furnished under license and may be used and
      8  1.1.2.2  nathanw  * copied only in accordance with the following terms and conditions.
      9  1.1.2.2  nathanw  * Subject to these conditions, you may download, copy, install,
     10  1.1.2.2  nathanw  * use, modify and distribute this software in source and/or binary
     11  1.1.2.2  nathanw  * form. No title or ownership is transferred hereby.
     12  1.1.2.2  nathanw  *
     13  1.1.2.2  nathanw  * 1) Any source code used, modified or distributed must reproduce
     14  1.1.2.2  nathanw  *    and retain this copyright notice and list of conditions as
     15  1.1.2.2  nathanw  *    they appear in the source file.
     16  1.1.2.2  nathanw  *
     17  1.1.2.2  nathanw  * 2) No right is granted to use any trade name, trademark, or logo of
     18  1.1.2.2  nathanw  *    Digital Equipment Corporation. Neither the "Digital Equipment
     19  1.1.2.2  nathanw  *    Corporation" name nor any trademark or logo of Digital Equipment
     20  1.1.2.2  nathanw  *    Corporation may be used to endorse or promote products derived
     21  1.1.2.2  nathanw  *    from this software without the prior written permission of
     22  1.1.2.2  nathanw  *    Digital Equipment Corporation.
     23  1.1.2.2  nathanw  *
     24  1.1.2.2  nathanw  * 3) This software is provided "AS-IS" and any express or implied
     25  1.1.2.2  nathanw  *    warranties, including but not limited to, any implied warranties
     26  1.1.2.2  nathanw  *    of merchantability, fitness for a particular purpose, or
     27  1.1.2.2  nathanw  *    non-infringement are disclaimed. In no event shall DIGITAL be
     28  1.1.2.2  nathanw  *    liable for any damages whatsoever, and in particular, DIGITAL
     29  1.1.2.2  nathanw  *    shall not be liable for special, indirect, consequential, or
     30  1.1.2.2  nathanw  *    incidental damages or damages for lost profits, loss of
     31  1.1.2.2  nathanw  *    revenue or loss of use, whether such damages arise in contract,
     32  1.1.2.2  nathanw  *    negligence, tort, under statute, in equity, at law or otherwise,
     33  1.1.2.2  nathanw  *    even if advised of the possibility of such damage.
     34  1.1.2.2  nathanw  */
     35  1.1.2.2  nathanw 
     36  1.1.2.2  nathanw /*-
     37  1.1.2.2  nathanw  * Copyright (c) 1993, 1994 Charles M. Hannum.
     38  1.1.2.2  nathanw  * Copyright (c) 1990 The Regents of the University of California.
     39  1.1.2.2  nathanw  * All rights reserved.
     40  1.1.2.2  nathanw  *
     41  1.1.2.2  nathanw  * This code is derived from software contributed to Berkeley by
     42  1.1.2.2  nathanw  * William Jolitz and Don Ahn.
     43  1.1.2.2  nathanw  *
     44  1.1.2.2  nathanw  * Redistribution and use in source and binary forms, with or without
     45  1.1.2.2  nathanw  * modification, are permitted provided that the following conditions
     46  1.1.2.2  nathanw  * are met:
     47  1.1.2.2  nathanw  * 1. Redistributions of source code must retain the above copyright
     48  1.1.2.2  nathanw  *    notice, this list of conditions and the following disclaimer.
     49  1.1.2.2  nathanw  * 2. Redistributions in binary form must reproduce the above copyright
     50  1.1.2.2  nathanw  *    notice, this list of conditions and the following disclaimer in the
     51  1.1.2.2  nathanw  *    documentation and/or other materials provided with the distribution.
     52  1.1.2.2  nathanw  * 3. All advertising materials mentioning features or use of this software
     53  1.1.2.2  nathanw  *    must display the following acknowledgement:
     54  1.1.2.2  nathanw  *	This product includes software developed by the University of
     55  1.1.2.2  nathanw  *	California, Berkeley and its contributors.
     56  1.1.2.2  nathanw  * 4. Neither the name of the University nor the names of its contributors
     57  1.1.2.2  nathanw  *    may be used to endorse or promote products derived from this software
     58  1.1.2.2  nathanw  *    without specific prior written permission.
     59  1.1.2.2  nathanw  *
     60  1.1.2.2  nathanw  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     61  1.1.2.2  nathanw  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     62  1.1.2.2  nathanw  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     63  1.1.2.2  nathanw  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     64  1.1.2.2  nathanw  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     65  1.1.2.2  nathanw  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     66  1.1.2.2  nathanw  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     67  1.1.2.2  nathanw  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     68  1.1.2.2  nathanw  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     69  1.1.2.2  nathanw  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     70  1.1.2.2  nathanw  * SUCH DAMAGE.
     71  1.1.2.2  nathanw  *
     72  1.1.2.2  nathanw  *	@(#)clock.c	7.2 (Berkeley) 5/12/91
     73  1.1.2.2  nathanw  */
     74  1.1.2.2  nathanw /*
     75  1.1.2.2  nathanw  * Mach Operating System
     76  1.1.2.2  nathanw  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
     77  1.1.2.2  nathanw  * All Rights Reserved.
     78  1.1.2.2  nathanw  *
     79  1.1.2.2  nathanw  * Permission to use, copy, modify and distribute this software and its
     80  1.1.2.2  nathanw  * documentation is hereby granted, provided that both the copyright
     81  1.1.2.2  nathanw  * notice and this permission notice appear in all copies of the
     82  1.1.2.2  nathanw  * software, derivative works or modified versions, and any portions
     83  1.1.2.2  nathanw  * thereof, and that both notices appear in supporting documentation.
     84  1.1.2.2  nathanw  *
     85  1.1.2.2  nathanw  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     86  1.1.2.2  nathanw  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     87  1.1.2.2  nathanw  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     88  1.1.2.2  nathanw  *
     89  1.1.2.2  nathanw  * Carnegie Mellon requests users of this software to return to
     90  1.1.2.2  nathanw  *
     91  1.1.2.2  nathanw  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     92  1.1.2.2  nathanw  *  School of Computer Science
     93  1.1.2.2  nathanw  *  Carnegie Mellon University
     94  1.1.2.2  nathanw  *  Pittsburgh PA 15213-3890
     95  1.1.2.2  nathanw  *
     96  1.1.2.2  nathanw  * any improvements or extensions that they make and grant Carnegie Mellon
     97  1.1.2.2  nathanw  * the rights to redistribute these changes.
     98  1.1.2.2  nathanw  */
     99  1.1.2.2  nathanw /*
    100  1.1.2.2  nathanw   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
    101  1.1.2.2  nathanw 
    102  1.1.2.2  nathanw 		All Rights Reserved
    103  1.1.2.2  nathanw 
    104  1.1.2.2  nathanw Permission to use, copy, modify, and distribute this software and
    105  1.1.2.2  nathanw its documentation for any purpose and without fee is hereby
    106  1.1.2.2  nathanw granted, provided that the above copyright notice appears in all
    107  1.1.2.2  nathanw copies and that both the copyright notice and this permission notice
    108  1.1.2.2  nathanw appear in supporting documentation, and that the name of Intel
    109  1.1.2.2  nathanw not be used in advertising or publicity pertaining to distribution
    110  1.1.2.2  nathanw of the software without specific, written prior permission.
    111  1.1.2.2  nathanw 
    112  1.1.2.2  nathanw INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
    113  1.1.2.2  nathanw INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
    114  1.1.2.2  nathanw IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
    115  1.1.2.2  nathanw CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    116  1.1.2.2  nathanw LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
    117  1.1.2.2  nathanw NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
    118  1.1.2.2  nathanw WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    119  1.1.2.2  nathanw */
    120  1.1.2.2  nathanw 
    121  1.1.2.2  nathanw /*
    122  1.1.2.2  nathanw  * Primitive clock interrupt routines.
    123  1.1.2.2  nathanw  */
    124  1.1.2.2  nathanw #include <sys/param.h>
    125  1.1.2.2  nathanw #include <sys/systm.h>
    126  1.1.2.2  nathanw #include <sys/time.h>
    127  1.1.2.2  nathanw #include <sys/kernel.h>
    128  1.1.2.2  nathanw #include <sys/device.h>
    129  1.1.2.2  nathanw 
    130  1.1.2.2  nathanw #include <machine/cpu.h>
    131  1.1.2.2  nathanw #include <machine/intr.h>
    132  1.1.2.2  nathanw #include <machine/pio.h>
    133  1.1.2.2  nathanw #include <arm/cpufunc.h>
    134  1.1.2.2  nathanw 
    135  1.1.2.2  nathanw #include <dev/isa/isareg.h>
    136  1.1.2.2  nathanw #include <dev/isa/isavar.h>
    137  1.1.2.2  nathanw #include <dev/ic/mc146818reg.h>
    138  1.1.2.2  nathanw #include <dev/ic/i8253reg.h>
    139  1.1.2.2  nathanw #include <shark/isa/nvram.h>
    140  1.1.2.2  nathanw #include <shark/isa/spkrreg.h>
    141  1.1.2.2  nathanw #include <shark/shark/hat.h>
    142  1.1.2.2  nathanw 
    143  1.1.2.3  nathanw void	sysbeepstop(void *);
    144  1.1.2.3  nathanw void	sysbeep(int, int);
    145  1.1.2.3  nathanw void	rtcinit(void);
    146  1.1.2.2  nathanw int     timer_hz_to_count(int);
    147  1.1.2.2  nathanw 
    148  1.1.2.3  nathanw static void findcpuspeed(void);
    149  1.1.2.3  nathanw static void init_isa_timer_tables(void);
    150  1.1.2.2  nathanw static void delayloop(int);
    151  1.1.2.3  nathanw static int  clockintr(void *);
    152  1.1.2.3  nathanw static int  gettick(void);
    153  1.1.2.3  nathanw 
    154  1.1.2.3  nathanw void startrtclock(void);
    155  1.1.2.2  nathanw 
    156  1.1.2.3  nathanw __inline u_int mc146818_read(void *, u_int);
    157  1.1.2.3  nathanw __inline void mc146818_write(void *, u_int, u_int);
    158  1.1.2.2  nathanw 
    159  1.1.2.2  nathanw #define	SECMIN	((unsigned)60)			/* seconds per minute */
    160  1.1.2.2  nathanw #define	SECHOUR	((unsigned)(60*SECMIN))		/* seconds per hour */
    161  1.1.2.2  nathanw #define	SECDAY	((unsigned)(24*SECHOUR))	/* seconds per day */
    162  1.1.2.2  nathanw #define	SECYR	((unsigned)(365*SECDAY))	/* seconds per common year */
    163  1.1.2.2  nathanw 
    164  1.1.2.2  nathanw __inline u_int
    165  1.1.2.2  nathanw mc146818_read(sc, reg)
    166  1.1.2.2  nathanw 	void *sc;					/* XXX use it? */
    167  1.1.2.2  nathanw 	u_int reg;
    168  1.1.2.2  nathanw {
    169  1.1.2.2  nathanw 
    170  1.1.2.2  nathanw 	outb(IO_RTC, reg);
    171  1.1.2.2  nathanw 	return (inb(IO_RTC+1));
    172  1.1.2.2  nathanw }
    173  1.1.2.2  nathanw 
    174  1.1.2.2  nathanw __inline void
    175  1.1.2.2  nathanw mc146818_write(sc, reg, datum)
    176  1.1.2.2  nathanw 	void *sc;					/* XXX use it? */
    177  1.1.2.2  nathanw 	u_int reg, datum;
    178  1.1.2.2  nathanw {
    179  1.1.2.2  nathanw 
    180  1.1.2.2  nathanw 	outb(IO_RTC, reg);
    181  1.1.2.2  nathanw 	outb(IO_RTC+1, datum);
    182  1.1.2.2  nathanw }
    183  1.1.2.2  nathanw 
    184  1.1.2.2  nathanw unsigned int count1024usec; /* calibrated loop variable (1024 microseconds) */
    185  1.1.2.2  nathanw 
    186  1.1.2.2  nathanw /* number of timer ticks in a Musec = 2^20 usecs */
    187  1.1.2.2  nathanw #define TIMER_MUSECFREQ\
    188  1.1.2.2  nathanw     (((((((TIMER_FREQ) * 1024) + 999) / 1000) * 1024) + 999) / 1000)
    189  1.1.2.2  nathanw #define TIMER_MUSECDIV(x) ((TIMER_MUSECFREQ+(x)/2)/(x))
    190  1.1.2.2  nathanw 
    191  1.1.2.2  nathanw /*
    192  1.1.2.2  nathanw  * microtime() makes use of the following globals.
    193  1.1.2.2  nathanw  * timer_msb_table[] and timer_lsb_table[] are used to compute the
    194  1.1.2.2  nathanw  * microsecond increment.
    195  1.1.2.2  nathanw  *
    196  1.1.2.2  nathanw  * time.tv_usec += isa_timer_msb_table[cnt_msb] + isa_timer_lsb_table[cnt_lsb];
    197  1.1.2.2  nathanw  */
    198  1.1.2.2  nathanw 
    199  1.1.2.2  nathanw u_short	isa_timer_msb_table[256];	/* timer->usec MSB */
    200  1.1.2.2  nathanw u_short	isa_timer_lsb_table[256];	/* timer->usec conversion for LSB */
    201  1.1.2.2  nathanw 
    202  1.1.2.2  nathanw /* 64 bit counts from timer 0 */
    203  1.1.2.2  nathanw struct count64 {
    204  1.1.2.2  nathanw   unsigned lo;   /* low 32 bits */
    205  1.1.2.2  nathanw   unsigned hi;   /* high 32 bits */
    206  1.1.2.2  nathanw };
    207  1.1.2.2  nathanw 
    208  1.1.2.2  nathanw #define TIMER0_ROLLOVER  0xFFFF  /* maximum rollover for 8254 counter */
    209  1.1.2.2  nathanw 
    210  1.1.2.2  nathanw struct count64 timer0count;
    211  1.1.2.2  nathanw struct count64 timer0_at_last_clockintr;
    212  1.1.2.2  nathanw unsigned       timer0last;
    213  1.1.2.2  nathanw 
    214  1.1.2.2  nathanw /*#define TESTHAT*/
    215  1.1.2.2  nathanw #ifdef TESTHAT
    216  1.1.2.2  nathanw #define HATSTACKSIZE 1024
    217  1.1.2.2  nathanw #define HATHZ  50000
    218  1.1.2.2  nathanw #define HATHZ2 10000
    219  1.1.2.2  nathanw unsigned char hatStack[HATSTACKSIZE];
    220  1.1.2.2  nathanw 
    221  1.1.2.2  nathanw unsigned testHatOn = 0;
    222  1.1.2.2  nathanw unsigned nHats = 0;
    223  1.1.2.2  nathanw unsigned nHatWedges = 0;
    224  1.1.2.2  nathanw unsigned fiqReason = 0;
    225  1.1.2.2  nathanw unsigned hatCount = 0;
    226  1.1.2.2  nathanw unsigned hatCount2 = 0;
    227  1.1.2.2  nathanw 
    228  1.1.2.2  nathanw void hatTest(int testReason)
    229  1.1.2.2  nathanw {
    230  1.1.2.2  nathanw   fiqReason |= testReason;
    231  1.1.2.2  nathanw   nHats++;
    232  1.1.2.2  nathanw 
    233  1.1.2.2  nathanw }
    234  1.1.2.2  nathanw 
    235  1.1.2.2  nathanw void hatWedge(int nFIQs)
    236  1.1.2.2  nathanw {
    237  1.1.2.2  nathanw     printf("Unwedging the HAT.  fiqs_happened = %d\n", nFIQs);
    238  1.1.2.2  nathanw     nHatWedges++;
    239  1.1.2.2  nathanw }
    240  1.1.2.2  nathanw #endif
    241  1.1.2.2  nathanw 
    242  1.1.2.2  nathanw void
    243  1.1.2.2  nathanw startrtclock()
    244  1.1.2.2  nathanw {
    245  1.1.2.2  nathanw 	findcpuspeed();		/* use the clock (while it's free)
    246  1.1.2.2  nathanw 					to find the cpu speed */
    247  1.1.2.2  nathanw 
    248  1.1.2.2  nathanw 	init_isa_timer_tables();
    249  1.1.2.2  nathanw 
    250  1.1.2.2  nathanw 	timer0count.lo = 0;
    251  1.1.2.2  nathanw 	timer0count.hi = 0;
    252  1.1.2.2  nathanw 	timer0_at_last_clockintr.lo = 0;
    253  1.1.2.2  nathanw 	timer0_at_last_clockintr.hi = 0;
    254  1.1.2.2  nathanw 	timer0last     = 0;
    255  1.1.2.2  nathanw 
    256  1.1.2.2  nathanw 	/* initialize 8253 clock */
    257  1.1.2.2  nathanw 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
    258  1.1.2.2  nathanw 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER % 256);
    259  1.1.2.2  nathanw 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER / 256);
    260  1.1.2.2  nathanw 
    261  1.1.2.2  nathanw #ifdef TESTHAT
    262  1.1.2.2  nathanw 	hatCount = timer_hz_to_count(HATHZ);
    263  1.1.2.2  nathanw 	hatCount2 = timer_hz_to_count(HATHZ2);
    264  1.1.2.2  nathanw 	printf("HAT test on @ %d Hz = %d ticks\n", HATHZ, hatCount);
    265  1.1.2.2  nathanw #endif
    266  1.1.2.2  nathanw }
    267  1.1.2.2  nathanw 
    268  1.1.2.2  nathanw static void
    269  1.1.2.2  nathanw init_isa_timer_tables()
    270  1.1.2.2  nathanw {
    271  1.1.2.2  nathanw 	int s;
    272  1.1.2.2  nathanw 	u_long t, msbmillion, quotient, remainder;
    273  1.1.2.2  nathanw 
    274  1.1.2.2  nathanw 	for (s = 0; s < 256; s++) {
    275  1.1.2.2  nathanw 	        /* LSB table is easy, just divide and round */
    276  1.1.2.2  nathanw 		t = ((u_long) s * 1000000 * 2) / TIMER_FREQ;
    277  1.1.2.2  nathanw 		isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1));
    278  1.1.2.2  nathanw 
    279  1.1.2.2  nathanw 		msbmillion = s * 1000000;
    280  1.1.2.2  nathanw 		quotient = msbmillion / TIMER_FREQ;
    281  1.1.2.2  nathanw 		remainder = msbmillion % TIMER_FREQ;
    282  1.1.2.2  nathanw 		t = (remainder * 256 * 2) / TIMER_FREQ;
    283  1.1.2.2  nathanw 		isa_timer_msb_table[s] =
    284  1.1.2.2  nathanw 		  (u_short)((t / 2) + (t & 1) + (quotient * 256));
    285  1.1.2.2  nathanw 
    286  1.1.2.2  nathanw #ifdef DIAGNOSTIC
    287  1.1.2.2  nathanw 		if ((s > 0) &&
    288  1.1.2.2  nathanw 		    (isa_timer_msb_table[s] <
    289  1.1.2.2  nathanw 		     (isa_timer_msb_table[s - 1] + isa_timer_lsb_table[0xFF])))
    290  1.1.2.2  nathanw 		  panic ("time tables not monotonic %d: %d < (%d + %d) = %d\n",
    291  1.1.2.2  nathanw 			 s, isa_timer_msb_table[s],
    292  1.1.2.2  nathanw 			 isa_timer_msb_table[s - 1],
    293  1.1.2.2  nathanw 			 isa_timer_lsb_table[0xFF],
    294  1.1.2.2  nathanw 			 isa_timer_msb_table[s - 1] +
    295  1.1.2.2  nathanw 			 isa_timer_lsb_table[0xFF]);
    296  1.1.2.2  nathanw #endif
    297  1.1.2.2  nathanw 	} /* END for */
    298  1.1.2.2  nathanw }
    299  1.1.2.2  nathanw 
    300  1.1.2.2  nathanw int
    301  1.1.2.2  nathanw timer_hz_to_count(timer_hz)
    302  1.1.2.2  nathanw 	int timer_hz;
    303  1.1.2.2  nathanw {
    304  1.1.2.2  nathanw 	u_long tval;
    305  1.1.2.2  nathanw 
    306  1.1.2.2  nathanw 	tval = (TIMER_FREQ * 2) / (u_long) timer_hz;
    307  1.1.2.2  nathanw 	tval = (tval / 2) + (tval & 0x1);
    308  1.1.2.2  nathanw 
    309  1.1.2.2  nathanw 	return (int)tval;
    310  1.1.2.2  nathanw 
    311  1.1.2.2  nathanw }
    312  1.1.2.2  nathanw 
    313  1.1.2.3  nathanw void gettimer0count(struct count64 *);
    314  1.1.2.3  nathanw 
    315  1.1.2.2  nathanw /* must be called at SPL_CLOCK or higher */
    316  1.1.2.2  nathanw void gettimer0count(pcount)
    317  1.1.2.2  nathanw 	struct count64 *pcount;
    318  1.1.2.2  nathanw {
    319  1.1.2.2  nathanw 	unsigned current, ticks, oldlo;
    320  1.1.2.2  nathanw 
    321  1.1.2.2  nathanw 	/*
    322  1.1.2.2  nathanw 	 * Latch the current value of the timer and then read it.
    323  1.1.2.2  nathanw 	 * This guarentees an atomic reading of the time.
    324  1.1.2.2  nathanw 	 */
    325  1.1.2.2  nathanw 
    326  1.1.2.2  nathanw 	current = gettick();
    327  1.1.2.2  nathanw 
    328  1.1.2.2  nathanw 	if (timer0last >= current)
    329  1.1.2.2  nathanw 	  ticks = timer0last - current;
    330  1.1.2.2  nathanw 	else
    331  1.1.2.2  nathanw 	  ticks = timer0last + (TIMER0_ROLLOVER - current);
    332  1.1.2.2  nathanw 
    333  1.1.2.2  nathanw 	timer0last = current;
    334  1.1.2.2  nathanw 
    335  1.1.2.2  nathanw 	oldlo = timer0count.lo;
    336  1.1.2.2  nathanw 
    337  1.1.2.2  nathanw 	if (oldlo > (timer0count.lo = oldlo + ticks)) /* carry? */
    338  1.1.2.2  nathanw 	  timer0count.hi++;
    339  1.1.2.2  nathanw 
    340  1.1.2.2  nathanw 	*pcount = timer0count;
    341  1.1.2.2  nathanw }
    342  1.1.2.2  nathanw 
    343  1.1.2.2  nathanw static int
    344  1.1.2.2  nathanw clockintr(arg)
    345  1.1.2.2  nathanw 	void *arg;
    346  1.1.2.2  nathanw {
    347  1.1.2.2  nathanw 	struct clockframe *frame = arg;		/* not strictly necessary */
    348  1.1.2.2  nathanw 	extern void isa_specific_eoi(int irq);
    349  1.1.2.2  nathanw #ifdef TESTHAT
    350  1.1.2.2  nathanw 	static int ticks = 0;
    351  1.1.2.2  nathanw #endif
    352  1.1.2.2  nathanw 	static int hatUnwedgeCtr = 0;
    353  1.1.2.2  nathanw 
    354  1.1.2.2  nathanw 	gettimer0count(&timer0_at_last_clockintr);
    355  1.1.2.2  nathanw 
    356  1.1.2.2  nathanw 	mc146818_read(NULL, MC_REGC); /* clear the clock interrupt */
    357  1.1.2.2  nathanw 
    358  1.1.2.2  nathanw 	/* check to see if the high-availability timer needs to be unwedged */
    359  1.1.2.2  nathanw 	if (++hatUnwedgeCtr >= (hz / HAT_MIN_FREQ)) {
    360  1.1.2.2  nathanw 	  hatUnwedgeCtr = 0;
    361  1.1.2.2  nathanw 	  hatUnwedge();
    362  1.1.2.2  nathanw 	}
    363  1.1.2.2  nathanw 
    364  1.1.2.2  nathanw #ifdef TESTHAT
    365  1.1.2.2  nathanw 	++ticks;
    366  1.1.2.2  nathanw 
    367  1.1.2.2  nathanw 	if (testHatOn && ((ticks & 0x3f) == 0)) {
    368  1.1.2.2  nathanw 	  if (testHatOn == 1) {
    369  1.1.2.2  nathanw 	    hatClkAdjust(hatCount2);
    370  1.1.2.2  nathanw 	    testHatOn = 2;
    371  1.1.2.2  nathanw 	  } else {
    372  1.1.2.2  nathanw 	    testHatOn = 0;
    373  1.1.2.2  nathanw 	    hatClkOff();
    374  1.1.2.2  nathanw 	    printf("hat off status: %d %d %x\n", nHats, nHatWedges, fiqReason);
    375  1.1.2.2  nathanw 	  }
    376  1.1.2.2  nathanw 	} else if (!testHatOn && (ticks & 0x1ff) == 0) {
    377  1.1.2.2  nathanw 	  printf("hat on status: %d %d %x\n", nHats, nHatWedges, fiqReason);
    378  1.1.2.2  nathanw 	  testHatOn = 1;
    379  1.1.2.2  nathanw 	  nHats = 0;
    380  1.1.2.2  nathanw 	  fiqReason = 0;
    381  1.1.2.2  nathanw 	  hatClkOn(hatCount, hatTest, 0xfeedface,
    382  1.1.2.2  nathanw 		   hatStack + HATSTACKSIZE - sizeof(unsigned),
    383  1.1.2.2  nathanw 		   hatWedge);
    384  1.1.2.2  nathanw 	}
    385  1.1.2.2  nathanw #endif
    386  1.1.2.2  nathanw 	hardclock(frame);
    387  1.1.2.2  nathanw 	return(0);
    388  1.1.2.2  nathanw }
    389  1.1.2.2  nathanw 
    390  1.1.2.2  nathanw static int
    391  1.1.2.2  nathanw gettick()
    392  1.1.2.2  nathanw {
    393  1.1.2.2  nathanw 	u_char lo, hi;
    394  1.1.2.2  nathanw 	u_int savedints;
    395  1.1.2.2  nathanw 
    396  1.1.2.2  nathanw 	/* Don't want someone screwing with the counter while we're here. */
    397  1.1.2.2  nathanw 	savedints = disable_interrupts(I32_bit);
    398  1.1.2.2  nathanw 	/* Select counter 0 and latch it. */
    399  1.1.2.2  nathanw 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
    400  1.1.2.2  nathanw 	lo = inb(IO_TIMER1 + TIMER_CNTR0);
    401  1.1.2.2  nathanw 	hi = inb(IO_TIMER1 + TIMER_CNTR0);
    402  1.1.2.2  nathanw 	restore_interrupts(savedints);
    403  1.1.2.2  nathanw 	return ((hi << 8) | lo);
    404  1.1.2.2  nathanw }
    405  1.1.2.2  nathanw 
    406  1.1.2.2  nathanw /* modifications from i386 to shark isa version:
    407  1.1.2.2  nathanw    - removed hardcoded "n -=" values that approximated the time to
    408  1.1.2.2  nathanw      calculate delay ticks
    409  1.1.2.2  nathanw    - made the time to calculate delay ticks almost negligable. 4 multiplies
    410  1.1.2.2  nathanw      = maximum of 12 cycles = 75ns on a slow SA-110, plus a bunch of shifts;
    411  1.1.2.2  nathanw      as opposed to 4 multiplies plus a bunch of divides.
    412  1.1.2.2  nathanw    - removed i386 assembly language hack
    413  1.1.2.2  nathanw    - put code in findcpuspeed that works even if FIRST_GUESS is orders
    414  1.1.2.2  nathanw      of magnitude low
    415  1.1.2.2  nathanw    - put code in delay() to use delayloop() for short delays
    416  1.1.2.2  nathanw    - microtime no longer in assembly language
    417  1.1.2.2  nathanw */
    418  1.1.2.2  nathanw 
    419  1.1.2.2  nathanw /*
    420  1.1.2.2  nathanw  * Wait "n" microseconds.
    421  1.1.2.2  nathanw  * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
    422  1.1.2.2  nathanw  * Note: timer had better have been programmed before this is first used!
    423  1.1.2.2  nathanw  * (Note that we use `rate generator' mode, which counts at 1:1; `square
    424  1.1.2.2  nathanw  * wave' mode counts at 2:1).
    425  1.1.2.2  nathanw  */
    426  1.1.2.2  nathanw void
    427  1.1.2.2  nathanw delay(n)
    428  1.1.2.2  nathanw 	unsigned n;
    429  1.1.2.2  nathanw {
    430  1.1.2.2  nathanw 	int tick, otick;
    431  1.1.2.2  nathanw 	int nticks;
    432  1.1.2.2  nathanw 
    433  1.1.2.2  nathanw 	if (n < 100) {
    434  1.1.2.2  nathanw 	  /* it can take a long time (1 usec or longer) just for 1 ISA read,
    435  1.1.2.2  nathanw 	     so it's best not to use the timer for short delays */
    436  1.1.2.2  nathanw 	  delayloop((n * count1024usec) >> 10);
    437  1.1.2.2  nathanw 	  return;
    438  1.1.2.2  nathanw 	}
    439  1.1.2.2  nathanw 
    440  1.1.2.2  nathanw 	/*
    441  1.1.2.2  nathanw 	 * Read the counter first, so that the rest of the setup overhead is
    442  1.1.2.2  nathanw 	 * counted.
    443  1.1.2.2  nathanw 	 */
    444  1.1.2.2  nathanw 	otick = gettick();
    445  1.1.2.2  nathanw 
    446  1.1.2.2  nathanw 	/*
    447  1.1.2.2  nathanw 	 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
    448  1.1.2.2  nathanw 	 * without any avoidable overflows.
    449  1.1.2.2  nathanw 	 */
    450  1.1.2.2  nathanw 	{
    451  1.1.2.2  nathanw 	        /* a Musec = 2^20 usec */
    452  1.1.2.2  nathanw 		int Musec = n >> 20,
    453  1.1.2.2  nathanw 		    usec = n & ((1 << 20) - 1);
    454  1.1.2.2  nathanw 		nticks
    455  1.1.2.2  nathanw 		  = (Musec * TIMER_MUSECFREQ) +
    456  1.1.2.2  nathanw 		    (usec * (TIMER_MUSECFREQ >> 20)) +
    457  1.1.2.2  nathanw 		    ((usec * ((TIMER_MUSECFREQ & ((1 <<20) - 1)) >>10)) >>10) +
    458  1.1.2.2  nathanw 		    ((usec * (TIMER_MUSECFREQ & ((1 << 10) - 1))) >> 20);
    459  1.1.2.2  nathanw 	}
    460  1.1.2.2  nathanw 
    461  1.1.2.2  nathanw 	while (nticks > 0) {
    462  1.1.2.2  nathanw 		tick = gettick();
    463  1.1.2.2  nathanw 		if (tick > otick)
    464  1.1.2.2  nathanw 			nticks -= TIMER0_ROLLOVER - (tick - otick);
    465  1.1.2.2  nathanw 		else
    466  1.1.2.2  nathanw 			nticks -= otick - tick;
    467  1.1.2.2  nathanw 		otick = tick;
    468  1.1.2.2  nathanw 	}
    469  1.1.2.2  nathanw 
    470  1.1.2.2  nathanw }
    471  1.1.2.2  nathanw 
    472  1.1.2.2  nathanw void
    473  1.1.2.2  nathanw sysbeepstop(arg)
    474  1.1.2.2  nathanw 	void *arg;
    475  1.1.2.2  nathanw {
    476  1.1.2.2  nathanw }
    477  1.1.2.2  nathanw 
    478  1.1.2.2  nathanw void
    479  1.1.2.2  nathanw sysbeep(pitch, period)
    480  1.1.2.2  nathanw 	int pitch, period;
    481  1.1.2.2  nathanw {
    482  1.1.2.2  nathanw }
    483  1.1.2.2  nathanw 
    484  1.1.2.2  nathanw #define FIRST_GUESS   0x2000
    485  1.1.2.2  nathanw 
    486  1.1.2.2  nathanw static void
    487  1.1.2.2  nathanw findcpuspeed()
    488  1.1.2.2  nathanw {
    489  1.1.2.2  nathanw 	int ticks;
    490  1.1.2.2  nathanw 	unsigned int guess = FIRST_GUESS;
    491  1.1.2.2  nathanw 
    492  1.1.2.2  nathanw 	while (1) { /* loop until accurate enough */
    493  1.1.2.2  nathanw 	  /* Put counter in count down mode */
    494  1.1.2.2  nathanw 	  outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
    495  1.1.2.2  nathanw 	  outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    496  1.1.2.2  nathanw 	  outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    497  1.1.2.2  nathanw 	  delayloop(guess);
    498  1.1.2.2  nathanw 
    499  1.1.2.2  nathanw 	  /* Read the value left in the counter */
    500  1.1.2.2  nathanw 	  /*
    501  1.1.2.2  nathanw 	   * Formula for delaycount is:
    502  1.1.2.2  nathanw 	   *  (loopcount * timer clock speed) / (counter ticks * 1000)
    503  1.1.2.2  nathanw 	   */
    504  1.1.2.2  nathanw 	  ticks = 0xFFFF - gettick();
    505  1.1.2.2  nathanw 	  if (ticks == 0) ticks = 1; /* just in case */
    506  1.1.2.2  nathanw 	  if (ticks < (TIMER_MUSECDIV(1024))) { /* not accurate enough */
    507  1.1.2.2  nathanw 	    guess *= max(2, (TIMER_MUSECDIV(1024) / ticks));
    508  1.1.2.2  nathanw 	    continue;
    509  1.1.2.2  nathanw 	  }
    510  1.1.2.2  nathanw 	  count1024usec = (guess * (TIMER_MUSECDIV(1024))) / ticks;
    511  1.1.2.2  nathanw 	  return;
    512  1.1.2.2  nathanw 	}
    513  1.1.2.2  nathanw }
    514  1.1.2.2  nathanw 
    515  1.1.2.2  nathanw static void
    516  1.1.2.2  nathanw delayloop(counts)
    517  1.1.2.2  nathanw {
    518  1.1.2.2  nathanw   while (counts--);
    519  1.1.2.2  nathanw }
    520  1.1.2.2  nathanw 
    521  1.1.2.2  nathanw void
    522  1.1.2.2  nathanw cpu_initclocks()
    523  1.1.2.2  nathanw {
    524  1.1.2.2  nathanw         unsigned hzval;
    525  1.1.2.2  nathanw 
    526  1.1.2.2  nathanw 	printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
    527  1.1.2.2  nathanw 
    528  1.1.2.2  nathanw 	/* install RTC interrupt handler */
    529  1.1.2.2  nathanw 	(void)isa_intr_establish(NULL, IRQ_RTC, IST_LEVEL, IPL_CLOCK,
    530  1.1.2.2  nathanw 				 clockintr, 0);
    531  1.1.2.2  nathanw 
    532  1.1.2.2  nathanw 	/* code for values of hz that don't divide 1000000 exactly */
    533  1.1.2.2  nathanw         tickfix = 1000000 - (hz * tick);
    534  1.1.2.2  nathanw         if (tickfix) {
    535  1.1.2.2  nathanw                 int ftp;
    536  1.1.2.2  nathanw 
    537  1.1.2.2  nathanw                 ftp = min(ffs(tickfix), ffs(hz));
    538  1.1.2.2  nathanw                 tickfix >>= (ftp - 1);
    539  1.1.2.2  nathanw                 tickfixinterval = hz >> (ftp - 1);
    540  1.1.2.2  nathanw         }
    541  1.1.2.2  nathanw 
    542  1.1.2.2  nathanw 	/* set  up periodic interrupt @ hz
    543  1.1.2.2  nathanw 	   this is the subset of hz values in kern_clock.c that are
    544  1.1.2.2  nathanw 	   supported by the ISA RTC */
    545  1.1.2.2  nathanw 	switch (hz) {
    546  1.1.2.2  nathanw 	case 64:
    547  1.1.2.2  nathanw 		hzval = MC_RATE_64_Hz;
    548  1.1.2.2  nathanw 		break;
    549  1.1.2.2  nathanw 	case 128:
    550  1.1.2.2  nathanw 		hzval = MC_RATE_128_Hz;
    551  1.1.2.2  nathanw 		break;
    552  1.1.2.2  nathanw 	case 256:
    553  1.1.2.2  nathanw 		hzval = MC_RATE_256_Hz;
    554  1.1.2.2  nathanw 		break;
    555  1.1.2.2  nathanw 	case 1024:
    556  1.1.2.2  nathanw 		hzval = MC_RATE_1024_Hz;
    557  1.1.2.2  nathanw 		break;
    558  1.1.2.2  nathanw 	default:
    559  1.1.2.3  nathanw 		panic("cannot configure hz = %d", hz);
    560  1.1.2.2  nathanw         }
    561  1.1.2.2  nathanw 
    562  1.1.2.2  nathanw 	rtcinit(); /* make sure basics are done by now */
    563  1.1.2.2  nathanw 
    564  1.1.2.2  nathanw 	/* blast values to set up clock interrupt */
    565  1.1.2.2  nathanw 	mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | hzval);
    566  1.1.2.2  nathanw 	/* enable periodic interrupt */
    567  1.1.2.2  nathanw 	mc146818_write(NULL, MC_REGB,
    568  1.1.2.2  nathanw 		       mc146818_read(NULL, MC_REGB) | MC_REGB_PIE);
    569  1.1.2.2  nathanw }
    570  1.1.2.2  nathanw 
    571  1.1.2.2  nathanw void
    572  1.1.2.2  nathanw rtcinit()
    573  1.1.2.2  nathanw {
    574  1.1.2.2  nathanw 	static int first_rtcopen_ever = 1;
    575  1.1.2.2  nathanw 
    576  1.1.2.2  nathanw 	if (!first_rtcopen_ever)
    577  1.1.2.2  nathanw 		return;
    578  1.1.2.2  nathanw 	first_rtcopen_ever = 0;
    579  1.1.2.2  nathanw 
    580  1.1.2.2  nathanw 	mc146818_write(NULL, MC_REGA,			/* XXX softc */
    581  1.1.2.2  nathanw 	    MC_BASE_32_KHz | MC_RATE_1024_Hz);
    582  1.1.2.2  nathanw 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR);	/* XXX softc */
    583  1.1.2.2  nathanw }
    584  1.1.2.2  nathanw 
    585  1.1.2.2  nathanw void
    586  1.1.2.2  nathanw setstatclockrate(arg)
    587  1.1.2.2  nathanw 	int arg;
    588  1.1.2.2  nathanw {
    589  1.1.2.2  nathanw }
    590  1.1.2.2  nathanw 
    591  1.1.2.2  nathanw /*
    592  1.1.2.2  nathanw  * void microtime(struct timeval *tvp)
    593  1.1.2.2  nathanw  *
    594  1.1.2.2  nathanw  * Fill in the specified timeval struct with the current time
    595  1.1.2.2  nathanw  * accurate to the microsecond.
    596  1.1.2.2  nathanw  */
    597  1.1.2.2  nathanw 
    598  1.1.2.2  nathanw void
    599  1.1.2.2  nathanw microtime(tvp)
    600  1.1.2.2  nathanw 	struct timeval *tvp;
    601  1.1.2.2  nathanw {
    602  1.1.2.2  nathanw         int s;
    603  1.1.2.2  nathanw 	unsigned lsb, msb;
    604  1.1.2.2  nathanw 	int tm;
    605  1.1.2.2  nathanw 	static struct timeval oldtv;
    606  1.1.2.2  nathanw 	struct count64 timer0current;
    607  1.1.2.2  nathanw 	int ticks;
    608  1.1.2.2  nathanw 
    609  1.1.2.2  nathanw 	s = splstatclock();
    610  1.1.2.2  nathanw 
    611  1.1.2.2  nathanw 	gettimer0count(&timer0current);
    612  1.1.2.2  nathanw 
    613  1.1.2.2  nathanw 	tm = time.tv_usec;
    614  1.1.2.2  nathanw 
    615  1.1.2.2  nathanw 	/* unsigned arithmetic should take care of overflow */
    616  1.1.2.2  nathanw 	/* with a >= 32 Hz clock, ticks will always be < 0x7FFF */
    617  1.1.2.2  nathanw 	ticks = (int)((unsigned)
    618  1.1.2.2  nathanw 		      (timer0current.lo - timer0_at_last_clockintr.lo));
    619  1.1.2.2  nathanw 
    620  1.1.2.2  nathanw #ifdef DIAGNOSTIC
    621  1.1.2.2  nathanw 	if ((ticks < 0) || (ticks > 0xffff))
    622  1.1.2.2  nathanw 	  printf("microtime bug: ticks = %x\n", ticks);
    623  1.1.2.2  nathanw #endif
    624  1.1.2.2  nathanw 
    625  1.1.2.2  nathanw 	while (ticks > 0) {
    626  1.1.2.2  nathanw 
    627  1.1.2.2  nathanw 	  if (ticks < 0xffff) {
    628  1.1.2.2  nathanw 	    msb = (ticks >> 8) & 0xFF;
    629  1.1.2.2  nathanw 	    lsb = ticks & 0xFF;
    630  1.1.2.2  nathanw 	  } else {
    631  1.1.2.2  nathanw 	    msb = 0xff;
    632  1.1.2.2  nathanw 	    lsb = 0xff;
    633  1.1.2.2  nathanw 	  }
    634  1.1.2.2  nathanw 
    635  1.1.2.2  nathanw 	  /* see comments above */
    636  1.1.2.2  nathanw 	  tm  += isa_timer_msb_table[msb] + isa_timer_lsb_table[lsb];
    637  1.1.2.2  nathanw 
    638  1.1.2.2  nathanw 	  /* for a 64 Hz RTC, ticks will never overflow table */
    639  1.1.2.2  nathanw 	  /* microtime will be less accurate if the RTC is < 36 Hz */
    640  1.1.2.2  nathanw 	  ticks -= 0xffff;
    641  1.1.2.2  nathanw 	}
    642  1.1.2.2  nathanw 
    643  1.1.2.2  nathanw 	tvp->tv_sec = time.tv_sec;
    644  1.1.2.2  nathanw 	if (tm >= 1000000) {
    645  1.1.2.2  nathanw 	  tvp->tv_sec += 1;
    646  1.1.2.2  nathanw 	  tm -= 1000000;
    647  1.1.2.2  nathanw 	}
    648  1.1.2.2  nathanw 
    649  1.1.2.2  nathanw 	tvp->tv_usec = tm;
    650  1.1.2.2  nathanw 
    651  1.1.2.2  nathanw 	/* Make sure the time has advanced. */
    652  1.1.2.2  nathanw 
    653  1.1.2.2  nathanw 	if (tvp->tv_sec == oldtv.tv_sec &&
    654  1.1.2.2  nathanw 	    tvp->tv_usec <= oldtv.tv_usec) {
    655  1.1.2.2  nathanw 		tvp->tv_usec = oldtv.tv_usec + 1;
    656  1.1.2.2  nathanw 		if (tvp->tv_usec >= 1000000) {
    657  1.1.2.2  nathanw 			tvp->tv_usec -= 1000000;
    658  1.1.2.2  nathanw 			++tvp->tv_sec;
    659  1.1.2.2  nathanw 		}
    660  1.1.2.2  nathanw 	}
    661  1.1.2.2  nathanw 
    662  1.1.2.2  nathanw 	oldtv = *tvp;
    663  1.1.2.2  nathanw 	(void)splx(s);
    664  1.1.2.2  nathanw }
    665  1.1.2.2  nathanw 
    666  1.1.2.2  nathanw /* End of clock.c */
    667