MIPS cpu-speed detection using mc146818 clock.
Compute CPU speed(MHz) and loop multiplier for DELAY() based on counting empty loop between mcclock ticks. New global: cpu_mhz. Change pmax/pmax/machdep.c to build baseboard model names from cpu_mhz. Set 'cpuspeed' for more realistic DELAY() on mips3 models. Mips CPU constants, testing, and calibration from D. Sean Davidson <davidson@zk3.dec.com> and Simon Burge <simonb@telstra.com.au>.
This commit is contained in:
parent
003ccf3b1c
commit
95a12ee943
|
@ -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
|
||||
|
|
|
@ -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 <sys/cdefs.h> /* RCS ID & Copyright macro defns */
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: mips_mcclock.c,v 1.1 1997/08/09 05:51:57 jonathan Exp $");
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/systm.h>
|
||||
#include <dev/ic/mc146818reg.h> /* clock rates */
|
||||
#include <sys/param.h> /* guaranteed to get splXXX() */
|
||||
#include <machine/clock_machdep.h>
|
||||
#include <mips/cpu.h> /* CPUISMIPS3 */
|
||||
#include <mips/mips/mips_mcclock.h>
|
||||
#include <pmax/pmax/clockreg.h> /* 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);
|
||||
}
|
|
@ -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
|
|
@ -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 <machine/pte.h>
|
||||
#include <machine/autoconf.h>
|
||||
#include <mips/locore.h> /* wbflush() */
|
||||
#include <mips/mips/mips_mcclock.h> /* mclock CPU setimation */
|
||||
|
||||
#ifdef DDB
|
||||
#include <mips/db_machdep.h>
|
||||
#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*/
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue