diff --git a/sys/arch/mips/conf/files.mips b/sys/arch/mips/conf/files.mips index 17afe1f42f4a..9d438f3a8f4f 100644 --- a/sys/arch/mips/conf/files.mips +++ b/sys/arch/mips/conf/files.mips @@ -3,6 +3,7 @@ file arch/mips/mips/db_interface.c ddb file arch/mips/mips/db_trace.c ddb file arch/mips/mips/cpu_exec.c file arch/mips/mips/mem.c +file arch/mips/mips/mips_mcclock.c clock # get CPU speed via mcclock file arch/mips/mips/pmap.c file arch/mips/mips/trap.c # interrupt, trap handlers file arch/mips/mips/vm_machdep.c diff --git a/sys/arch/mips/mips/mips_mcclock.c b/sys/arch/mips/mips/mips_mcclock.c new file mode 100644 index 000000000000..485b4415ddb5 --- /dev/null +++ b/sys/arch/mips/mips/mips_mcclock.c @@ -0,0 +1,275 @@ +/* $NetBSD: mips_mcclock.c,v 1.1 1997/08/09 05:51:57 jonathan Exp $ */ + +/* + * Copyright (c) 1997 Jonathan Stone (hereinafter referred to as the author) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jonathan Stone for + * the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include /* RCS ID & Copyright macro defns */ + +__KERNEL_RCSID(0, "$NetBSD: mips_mcclock.c,v 1.1 1997/08/09 05:51:57 jonathan Exp $"); + + +#include +#include +#include /* clock rates */ +#include /* guaranteed to get splXXX() */ +#include +#include /* CPUISMIPS3 */ +#include +#include /* XXX struct chiptime */ + + +extern u_int mips_read_causereg __P((void)); + +unsigned mips_mc_cpuspeed __P(( + volatile struct chiptime *mcaddr, int clockmask, + int (*tickpollfn) __P((volatile struct chiptime *mcclock_addr, + int clockmask)) )); + +unsigned mips_mcclock_to_mhz __P((unsigned iters)); + +int mips_mcclock_tickloop __P((volatile struct chiptime *mcclock_addr, + int clockmask)); + + +/* + * Estimate CPU cycle speed by counting cycles (acutally executions of a + * one-line loop) between two adjacent ticks of an mc146818 clock. + * Return loop iteration count so hand-calibrated MD code can + * estimate clock speed from cycles. + * + * Runs before CPU is attached (so we can print CPU speed) which is + * before the clock is attached, so we can't use the normal clock driver. + */ +unsigned +mips_mc_cpuspeed(mcclock_addr, clockmask, tickpollfn) + volatile struct chiptime *mcclock_addr; + int clockmask; + int (*tickpollfn) __P((volatile struct chiptime *mcclock_addr, + int clockmask)); +{ + register int s; + register int iters = 0; + int saved_rega, saved_regb; + + + /* + * Block all interrupts, including clock ticks. + */ + s = splhigh(); + + /* + * Enable periodic interrupst on the mc146818, + * and set it up for 256Hz (4ms) interrupts. + * Save any state we change so we can restore it on exit. + */ + saved_rega = mcclock_addr->rega; + saved_regb = mcclock_addr->regb; + +#if 0 + mcclock_addr->rega = (saved_rega & ~MC_BASE_RESET) | MC_RATE_256_Hz; + mcclock_addr->regb = MC_REGB_BINARY|MC_REGB_24HR|MC_REGB_PIE; +#else + mcclock_addr->rega = MC_BASE_32_KHz | MC_RATE_256_Hz; + mcclock_addr->regb = MC_REGB_BINARY|MC_REGB_24HR|MC_REGB_PIE| MC_REGB_SQWE; +#endif + /* count loop iterations between ticks */ + iters = (*tickpollfn)(mcclock_addr, clockmask); + + /* Restore mcclock registers */ + mcclock_addr->rega = saved_rega; + mcclock_addr->regb = saved_regb; + + splx(s); + + /* + * Compute approximate CPU speed in MHz, and an + * appropriate base for DELAY() and delay(), from + * the number of completed iterations. + */ + cpu_mhz = mips_mcclock_to_mhz(iters); + +#if defined(DEBUG) || defined(DIAGNOSTIC) || 1 + printf("mcclock: iters %d computed MHz %d, instrs per usec=%d\n", + iters, cpu_mhz, cpuspeed); +#endif + return (iters); +} + + +/* + * Poll mcclock chip for the next tick interrupt and count + * instructions until the subsequent tick. + * + * XXX Assumes the mcclock chip has exclusive use of a CPU interrupt line. + * XXX Assumes bus access to clock registers is cheap (not a function call). + * MD alternatives must be used where this doesn't hold. + */ + +int +mips_mcclock_tickloop(mcclock_addr, clockmask) + volatile struct chiptime *mcclock_addr; + int clockmask; +{ + register int iters = 0; + register volatile int junk; + + /* clear any old pending interrupts */ + junk = mcclock_addr->regc; + junk++; junk++; junk++; junk++; + + /* Poll clock interrupt, waiting for next tick to happen. */ + while ((mips_read_causereg() & clockmask) == 0) + ; + + /* Ack the mc146818 interrupt caused by starting tick. */ + junk = mcclock_addr->regc; + + junk++; junk++; junk++; junk++; + + /* Count loops until next tick-interrupt request occurs (4ms). */ + if (CPUISMIPS3) { + while ((mips_read_causereg() & clockmask) == 0) { + __asm __volatile ("nop; nop; nop; nop"); + iters++; + } + } else { + while ((mips_read_causereg() & clockmask) == 0) + iters++; + } + + /* Ack the interrupt from the just-gone-off tick */ + junk = mcclock_addr->regc; + + return (iters); +} + + +/* + * Compute MHz and DELAY() constants using the default + * polling function. + */ +unsigned +mc_cpuspeed(mcclock_addr, clockmask) + volatile struct chiptime *mcclock_addr; + int clockmask; +{ + return mips_mc_cpuspeed(mcclock_addr, clockmask, + mips_mcclock_tickloop); +} + + + +/* + * mips_mcclock_to_mhz(iters) -- convert an mcclock cycles-per-tick count + * to a CPU speed in MHz. + * + * Side Effects: + * set the global variables "cpuspeed", used by DELAY() and delay() + * as an instructions-per-microsecond multiplier, to an value appropriate + * for the estimated clock speed. + */ +unsigned +mips_mcclock_to_mhz(unsigned iters) +{ + register unsigned mhz = 0; + + /* XXX KN01? */ + + /* + * Measured thresholds for Digital systems from Sean Davidson. + * + * r3000-core DECstations values fit to: + * iters per 4ms tick = 425 * MHz) + * instructions per mhz = kHz * 575 + * with about 2 Mhz slop to allow for variation. + */ + +#ifdef MIPS3 + if (CPUISMIPS3) { + if (iters < 18100) { + /* error */ + printf("mcclock loop count %d too low for r4000\n", + iters); + mhz = 45; + cpuspeed = 90; /* XXX */ + } else if (iters < 20000) { + mhz = 50; + cpuspeed = 100; /* XXX */ + } else if (iters < 24110) { + mhz = 60; + cpuspeed = 110; /* XXX */ + } else if (iters < 27140) { + mhz = 67; + cpuspeed = 130; /* XXX */ + } else if (iters < 30000) { + mhz = 75; + cpuspeed = 150; /* XXX */ + } + } +#endif /* MIPS3 */ + +#ifdef MIPS1 + if (!CPUISMIPS3) { + if (iters < 8800) { + mhz = 20; + cpuspeed = 11; + } else if (iters < 11300) { + mhz = 25; + cpuspeed = 13; + } else if (iters < 14000) { + mhz = 33; + cpuspeed = 19; + } else if (iters < 15000) { + mhz = 36; + cpuspeed = 21; + } else if (iters < 16000) { + mhz = 40; + cpuspeed = 23; + } else if (iters < 18800) { + mhz = 45; + cpuspeed = 25; + } else if (iters < 21000) { + mhz = 50; + cpuspeed = 29; + } else if (iters < 26000) { + mhz = 60; + cpuspeed = 35; + } else { + /* XXX */ + mhz = 70; + cpuspeed = 40; + } + } +#endif /* MIPS1 */ + + return (mhz); +} diff --git a/sys/arch/mips/mips/mips_mcclock.h b/sys/arch/mips/mips/mips_mcclock.h new file mode 100644 index 000000000000..fda0d710336e --- /dev/null +++ b/sys/arch/mips/mips/mips_mcclock.h @@ -0,0 +1,51 @@ +/* $NetBSD: mips_mcclock.h,v 1.1 1997/08/09 05:51:58 jonathan Exp $ */ + +/* + * Copyright (c) 1997 Jonathan Stone (hereinafter referred to as the author) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jonathan Stone for + * the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_MCCLOCK_H_ +#define _MIPS_MCCLOCK_H_ + + +/* + * Estimate CPU speed and multiplier for DELAY() by polling mcclock, + * couting iterations of an loop between successive ticks. + */ +struct chiptime; +unsigned mc_cpuspeed __P((volatile struct chiptime *mcaddr, int clockmask)); + +/* + * CPU speed in MHz, as estimated by mc_cpuspeed(). Read-only. + */ +extern int cpu_mhz; + +#endif diff --git a/sys/arch/pmax/pmax/machdep.c b/sys/arch/pmax/pmax/machdep.c index 179ea4fac721..4d3fab7066ef 100644 --- a/sys/arch/pmax/pmax/machdep.c +++ b/sys/arch/pmax/pmax/machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.93 1997/08/06 12:03:37 jonathan Exp $ */ +/* $NetBSD: machdep.c,v 1.94 1997/08/09 05:51:59 jonathan Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -85,6 +85,8 @@ #include #include #include /* wbflush() */ +#include /* mclock CPU setimation */ + #ifdef DDB #include #endif @@ -244,6 +246,8 @@ void kn02_enable_intr __P ((u_int slotno, #ifdef DS5000_100 void kmin_enable_intr __P ((u_int slotno, int (*handler) (intr_arg_t sc), intr_arg_t sc, int onoff)); +void kmin_mcclock_cpuspeed __P((volatile struct chiptime *mcclock_addr, + int clockmask)); #endif /*DS5000_100*/ #ifdef DS5000_25 @@ -286,7 +290,6 @@ struct proc nullproc; /* for use by switch_exit() */ /* locore callback-vector setup */ extern void mips_vector_init __P((void)); - /* * Do all the stuff that locore normally does before calling main(). * Process arguments passed to us by the prom monitor. @@ -508,6 +511,8 @@ mach_init(argc, argv, code, cv) mcclock_addr = (volatile struct chiptime *) MIPS_PHYS_TO_KSEG1(KN01_SYS_CLOCK); + mc_cpuspeed(mcclock_addr, MIPS_INT_MASK_3); + strcpy(cpu_model, "3100"); break; #endif /* DS3100 */ @@ -563,6 +568,7 @@ mach_init(argc, argv, code, cv) MIPS_PHYS_TO_KSEG1(KN02_SYS_CLOCK); } + mc_cpuspeed(mcclock_addr, MIPS_INT_MASK_1); strcpy(cpu_model, "5000/200"); break; #endif /* DS5000_200 */ @@ -594,7 +600,7 @@ mach_init(argc, argv, code, cv) Mach_splstatclock = splhigh; mcclock_addr = (volatile struct chiptime *) MIPS_PHYS_TO_KSEG1(KMIN_SYS_CLOCK); - + kmin_mcclock_cpuspeed(mcclock_addr, MIPS_INT_MASK_3); /* * Initialize interrupts. @@ -607,7 +613,8 @@ mach_init(argc, argv, code, cv) (u_int*)MIPS_PHYS_TO_KSEG1(KMIN_REG_TIMEOUT); (*Mach_reset_addr) = 0; - strcpy(cpu_model, (CPUISMIPS3)? "5000/150": "5000/1xx"); + sprintf(cpu_model, (CPUISMIPS3)? "5000/1%d": "5000/%d", + cpu_mhz); /* * The kmin memory hardware seems to wrap memory addresses @@ -654,6 +661,7 @@ mach_init(argc, argv, code, cv) Mach_splstatclock = cpu_spl3; mcclock_addr = (volatile struct chiptime *) MIPS_PHYS_TO_KSEG1(XINE_SYS_CLOCK); + mc_cpuspeed(mcclock_addr, MIPS_INT_MASK_1); /* * Initialize interrupts. @@ -665,7 +673,7 @@ mach_init(argc, argv, code, cv) (u_int*)MIPS_PHYS_TO_KSEG1(XINE_REG_TIMEOUT); (*Mach_reset_addr) = 0; - strcpy(cpu_model, (CPUISMIPS3) ? "5000/50": "5000/25"); + sprintf(cpu_model, "5000/%d", cpu_mhz); break; #endif /*DS5000_25*/ @@ -699,6 +707,7 @@ mach_init(argc, argv, code, cv) Mach_splstatclock = cpu_spl1; mcclock_addr = (volatile struct chiptime *) MIPS_PHYS_TO_KSEG1(KN03_SYS_CLOCK); + mc_cpuspeed(mcclock_addr, MIPS_INT_MASK_1); asic_init(0); /* @@ -714,7 +723,7 @@ mach_init(argc, argv, code, cv) /* clear any memory errors from probes */ *Mach_reset_addr = 0; - strcpy(cpu_model, (CPUISMIPS3) ? "5000/260" : "5000/240"); + sprintf(cpu_model, "5000/2%d", cpu_mhz); break; #endif /* DS5000_240 */ @@ -1564,6 +1573,35 @@ kmin_enable_intr(slotno, handler, sc, on) tc_slot_info[slotno].sc = 0; } } + +/* + * Count instructions between 4ms mcclock interrupt requests, + * using the ioasic clock-interrupt-pending bit to determine + * when clock ticks occur. + * Set up iosiac to allow only clock interrupts, then + * call + */ +void +kmin_mcclock_cpuspeed(mcclock_addr, clockmask) + volatile struct chiptime *mcclock_addr; + int clockmask; +{ + register volatile u_int * ioasic_intrmaskp = + (volatile u_int *)MIPS_PHYS_TO_KSEG1(KMIN_REG_IMSK); + + register int saved_imask = *ioasic_intrmaskp; + + /* Allow only clock interrupts through ioasic. */ + *ioasic_intrmaskp = KMIN_INTR_CLOCK; + wbflush(); + + mc_cpuspeed(mcclock_addr, clockmask); + + *ioasic_intrmaskp = saved_imask; + wbflush(); +} + + #endif /*DS5000_100*/