Add sys/kern/kern_cctr.c, which contains MI cpu cyclecounter based
timecounter(9) support functions split out from sys/arch/x86/x86/tsc.c. Written by and ok'ed to commit by kardel@. Also add <sys/cctr.h>, which is copied from #ifdef __HAVE_TIMECOUNTER part of <sys/cc_microtime.h> to migrate MI kern_cctr.c per each port.
This commit is contained in:
parent
9293272695
commit
ccee2438df
302
sys/kern/kern_cctr.c
Normal file
302
sys/kern/kern_cctr.c
Normal file
@ -0,0 +1,302 @@
|
||||
/* $NetBSD: kern_cctr.c,v 1.1 2007/07/21 11:47:07 tsutsui Exp $ */
|
||||
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* re-implementation of TSC for MP systems merging cc_microtime and
|
||||
* TSC for timecounters by Frank Kardel
|
||||
*
|
||||
* 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 the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``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 FOUNDATION OR CONTRIBUTORS
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* basic calibration ideas are (kern_microtime.c): */
|
||||
/******************************************************************************
|
||||
* *
|
||||
* Copyright (c) David L. Mills 1993, 1994 *
|
||||
* *
|
||||
* Permission to use, copy, modify, and distribute this software and its *
|
||||
* documentation for any purpose and without fee is hereby granted, provided *
|
||||
* that the above copyright notice appears in all copies and that both the *
|
||||
* copyright notice and this permission notice appear in supporting *
|
||||
* documentation, and that the name University of Delaware not be used in *
|
||||
* advertising or publicity pertaining to distribution of the software *
|
||||
* without specific, written prior permission. The University of Delaware *
|
||||
* makes no representations about the suitability this software for any *
|
||||
* purpose. It is provided "as is" without express or implied warranty. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
/* reminiscents from older version of this file are: */
|
||||
/*-
|
||||
* Copyright (c) 1998-2003 Poul-Henning Kamp
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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>
|
||||
/* __FBSDID("$FreeBSD: src/sys/i386/i386/tsc.c,v 1.204 2003/10/21 18:28:34 silby Exp $"); */
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_cctr.c,v 1.1 2007/07/21 11:47:07 tsutsui Exp $");
|
||||
|
||||
#include "opt_multiprocessor.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/timetc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/power.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpu_counter.h>
|
||||
|
||||
/* XXX make cc_timecounter.tc_frequency settable by sysctl() */
|
||||
|
||||
static timecounter_get_t cc_get_timecount;
|
||||
static timecounter_pps_t cc_calibrate;
|
||||
|
||||
void cc_calibrate_cpu(struct cpu_info *);
|
||||
|
||||
static int64_t cc_cal_val; /* last calibrate time stamp */
|
||||
|
||||
static struct timecounter cc_timecounter = {
|
||||
.tc_get_timecount = cc_get_timecount,
|
||||
.tc_poll_pps = cc_calibrate,
|
||||
.tc_counter_mask = ~0u,
|
||||
.tc_frequency = 0,
|
||||
.tc_name = "unkown cycle counter",
|
||||
/*
|
||||
* don't pick cycle counter automatically
|
||||
* if frequency changes might affect cycle counter
|
||||
*/
|
||||
.tc_quality = -100000,
|
||||
|
||||
.tc_priv = NULL,
|
||||
.tc_next = NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* initialize cycle counter based timecounter
|
||||
*/
|
||||
struct timecounter *
|
||||
cc_init(uint64_t freq, const char *name, int quality)
|
||||
{
|
||||
|
||||
cc_timecounter.tc_frequency = freq;
|
||||
cc_timecounter.tc_name = name;
|
||||
cc_timecounter.tc_quality = quality;
|
||||
tc_init(&cc_timecounter);
|
||||
|
||||
return &cc_timecounter;
|
||||
}
|
||||
|
||||
/*
|
||||
* pick up tick count scaled to reference tick count
|
||||
*/
|
||||
static u_int
|
||||
cc_get_timecount(struct timecounter *tc)
|
||||
{
|
||||
struct cpu_info *ci = curcpu();
|
||||
int64_t rcc, cc;
|
||||
u_int gen;
|
||||
|
||||
if (ci->ci_cc.cc_denom == 0) {
|
||||
/*
|
||||
* This is our first time here on this CPU. Just
|
||||
* start with reasonable initial values.
|
||||
*/
|
||||
ci->ci_cc.cc_cc = cpu_counter32();
|
||||
ci->ci_cc.cc_val = 0;
|
||||
if (ci->ci_cc.cc_gen == 0)
|
||||
ci->ci_cc.cc_gen++;
|
||||
|
||||
ci->ci_cc.cc_denom = cpu_frequency(ci);
|
||||
if (ci->ci_cc.cc_denom == 0)
|
||||
ci->ci_cc.cc_denom = cc_timecounter.tc_frequency;
|
||||
ci->ci_cc.cc_delta = ci->ci_cc.cc_denom;
|
||||
}
|
||||
|
||||
/*
|
||||
* read counter and re-read when the re-calibration
|
||||
* strikes inbetween
|
||||
*/
|
||||
do {
|
||||
/* pick up current generation number */
|
||||
gen = ci->ci_cc.cc_gen;
|
||||
|
||||
/* determine local delta ticks */
|
||||
cc = cpu_counter32() - ci->ci_cc.cc_cc;
|
||||
if (cc < 0)
|
||||
cc += 0x100000000LL;
|
||||
|
||||
/* scale to primary */
|
||||
rcc = (cc * ci->ci_cc.cc_delta) / ci->ci_cc.cc_denom
|
||||
+ ci->ci_cc.cc_val;
|
||||
} while (gen == 0 || gen != ci->ci_cc.cc_gen);
|
||||
|
||||
return rcc;
|
||||
}
|
||||
|
||||
/*
|
||||
* called once per clock tick via the pps callback
|
||||
* for the calibration of the TSC counters.
|
||||
* it is called only for the PRIMARY cpu. all
|
||||
* other cpus are called via a broadcast IPI
|
||||
* calibration interval is 1 second - we call
|
||||
* the calobration code only every hz calls
|
||||
*/
|
||||
static void
|
||||
cc_calibrate(struct timecounter *tc)
|
||||
{
|
||||
static int calls;
|
||||
struct cpu_info *ci;
|
||||
|
||||
/*
|
||||
* XXX: for high interrupt frequency
|
||||
* support: ++calls < hz / tc_tick
|
||||
*/
|
||||
if (++calls < hz)
|
||||
return;
|
||||
|
||||
calls = 0;
|
||||
ci = curcpu();
|
||||
/* pick up reference ticks */
|
||||
cc_cal_val = cpu_counter32();
|
||||
|
||||
#if defined(MULTIPROCESSOR)
|
||||
cc_calibrate_mp(ci);
|
||||
#endif
|
||||
cc_calibrate_cpu(ci);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called about once per second directly by the master
|
||||
* processor and via an interprocessor interrupt for other processors.
|
||||
* It determines the CC frequency of each processor relative to the
|
||||
* master clock and the time this determination is made. These values
|
||||
* are used by cc_get_timecount() to interpolate the ticks between
|
||||
* timer interrupts. Note that we assume the kernel variables have
|
||||
* been zeroed early in life.
|
||||
*/
|
||||
void
|
||||
cc_calibrate_cpu(struct cpu_info *ci)
|
||||
{
|
||||
u_int gen;
|
||||
int64_t val;
|
||||
int64_t delta, denom;
|
||||
int s;
|
||||
#ifdef TIMECOUNTER_DEBUG
|
||||
int64_t factor, old_factor;
|
||||
#endif
|
||||
val = cc_cal_val;
|
||||
|
||||
s = splhigh();
|
||||
/* create next generation number */
|
||||
gen = ci->ci_cc.cc_gen;
|
||||
gen++;
|
||||
if (gen == 0)
|
||||
gen++;
|
||||
|
||||
/* update in progress */
|
||||
ci->ci_cc.cc_gen = 0;
|
||||
|
||||
denom = ci->ci_cc.cc_cc;
|
||||
ci->ci_cc.cc_cc = cpu_counter32();
|
||||
|
||||
if (ci->ci_cc.cc_denom == 0) {
|
||||
/*
|
||||
* This is our first time here on this CPU. Just
|
||||
* start with reasonable initial values.
|
||||
*/
|
||||
ci->ci_cc.cc_val = val;
|
||||
ci->ci_cc.cc_denom = cpu_frequency(ci);
|
||||
if (ci->ci_cc.cc_denom == 0)
|
||||
ci->ci_cc.cc_denom = cc_timecounter.tc_frequency;;
|
||||
ci->ci_cc.cc_delta = ci->ci_cc.cc_denom;
|
||||
ci->ci_cc.cc_gen = gen;
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TIMECOUNTER_DEBUG
|
||||
old_factor = (ci->ci_cc.cc_delta * 1000 ) / ci->ci_cc.cc_denom;
|
||||
#endif
|
||||
|
||||
/* local ticks per period */
|
||||
denom = ci->ci_cc.cc_cc - denom;
|
||||
if (denom < 0)
|
||||
denom += 0x100000000LL;
|
||||
|
||||
ci->ci_cc.cc_denom = denom;
|
||||
|
||||
/* reference ticks per period */
|
||||
delta = val - ci->ci_cc.cc_val;
|
||||
if (delta < 0)
|
||||
delta += 0x100000000LL;
|
||||
|
||||
ci->ci_cc.cc_val = val;
|
||||
ci->ci_cc.cc_delta = delta;
|
||||
|
||||
/* publish new generation number */
|
||||
ci->ci_cc.cc_gen = gen;
|
||||
splx(s);
|
||||
|
||||
#ifdef TIMECOUNTER_DEBUG
|
||||
factor = (delta * 1000) / denom - old_factor;
|
||||
if (factor < 0)
|
||||
factor = -factor;
|
||||
|
||||
if (factor > old_factor / 10)
|
||||
printf("cc_calibrate_cpu[%lu]: 10%% exceeded - delta %"
|
||||
PRId64 ", denom %" PRId64 ", factor %" PRId64
|
||||
", old factor %" PRId64"\n", ci->ci_cpuid,
|
||||
delta, denom, (delta * 1000) / denom, old_factor);
|
||||
#endif /* TIMECOUNTER_DEBUG */
|
||||
}
|
57
sys/sys/cctr.h
Normal file
57
sys/sys/cctr.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* $NetBSD: cctr.h,v 1.1 2007/07/21 11:47:08 tsutsui Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004 The NetBSD Foundation, Inc.
|
||||
* 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 the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``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 FOUNDATION OR CONTRIBUTORS
|
||||
* 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 _SYS_CCTR_H_
|
||||
#define _SYS_CCTR_H_
|
||||
|
||||
/*
|
||||
* Variables used by cycle counter in kern_cctr.c.
|
||||
*/
|
||||
struct cctr_state {
|
||||
volatile u_int cc_gen; /* generation number for this data set */
|
||||
volatile int64_t cc_val; /* reference CC value at calibration time */
|
||||
volatile int64_t cc_cc; /* local CC value at calibration time */
|
||||
volatile int64_t cc_delta; /* reference CC difference for
|
||||
last calibration period */
|
||||
volatile int64_t cc_denom; /* local CC difference for
|
||||
last calibration period */
|
||||
};
|
||||
|
||||
struct cpu_info;
|
||||
|
||||
void cc_calibrate_cpu(struct cpu_info *);
|
||||
struct timecounter *cc_init(uint64_t, const char *, int);
|
||||
|
||||
#endif /* _SYS_CCTR_H_ */
|
Loading…
Reference in New Issue
Block a user