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