tsc.c revision 110370
14Srgrimes/*-
24Srgrimes * Copyright (c) 1990 The Regents of the University of California.
34Srgrimes * All rights reserved.
44Srgrimes *
54Srgrimes * This code is derived from software contributed to Berkeley by
64Srgrimes * William Jolitz and Don Ahn.
74Srgrimes *
84Srgrimes * Redistribution and use in source and binary forms, with or without
94Srgrimes * modification, are permitted provided that the following conditions
104Srgrimes * are met:
114Srgrimes * 1. Redistributions of source code must retain the above copyright
124Srgrimes *    notice, this list of conditions and the following disclaimer.
134Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
144Srgrimes *    notice, this list of conditions and the following disclaimer in the
154Srgrimes *    documentation and/or other materials provided with the distribution.
164Srgrimes * 3. All advertising materials mentioning features or use of this software
174Srgrimes *    must display the following acknowledgement:
184Srgrimes *	This product includes software developed by the University of
194Srgrimes *	California, Berkeley and its contributors.
204Srgrimes * 4. Neither the name of the University nor the names of its contributors
214Srgrimes *    may be used to endorse or promote products derived from this software
224Srgrimes *    without specific prior written permission.
234Srgrimes *
244Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
254Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
264Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
274Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
284Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
294Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
304Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
314Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
324Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
334Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
344Srgrimes * SUCH DAMAGE.
354Srgrimes *
36619Srgrimes *	from: @(#)clock.c	7.2 (Berkeley) 5/12/91
3750477Speter * $FreeBSD: head/sys/i386/i386/tsc.c 110370 2003-02-05 09:20:40Z phk $
384Srgrimes */
394Srgrimes
403185Ssos/*
4119173Sbde * Routines to handle clock hardware.
4219173Sbde */
4319173Sbde
4419173Sbde/*
453185Ssos * inittodr, settodr and support routines written
463185Ssos * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at>
473185Ssos *
483185Ssos * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94
492913Sache */
502913Sache
5116299Spst#include "opt_clock.h"
5213228Swollman
532056Swollman#include <sys/param.h>
54110039Sphk#include <sys/stdint.h>
552056Swollman#include <sys/systm.h>
562056Swollman#include <sys/time.h>
5758377Sphk#include <sys/timetc.h>
582056Swollman#include <sys/kernel.h>
5915508Sbde#include <sys/sysctl.h>
6085835Siwasaki#include <sys/power.h>
614180Sbde#include <machine/clock.h>
6232054Sphk#include <machine/md_var.h>
6332054Sphk#include <machine/specialreg.h>
6415508Sbde
65110039Sphkuint64_t	tsc_freq;
66110370Sphkint		tsc_is_broken;
67110370Sphku_int		tsc_present;
681390Ssos
6992765Salfredstatic	unsigned tsc_get_timecount(struct timecounter *tc);
7017353Sbde
7140610Sphkstatic struct timecounter tsc_timecounter = {
7233690Sphk	tsc_get_timecount,	/* get_timecount */
7336741Sphk	0,			/* no poll_pps */
7436198Sphk 	~0u,			/* counter_mask */
7533690Sphk	0,			/* frequency */
7633690Sphk	 "TSC"			/* name */
7733690Sphk};
7833690Sphk
791390Ssosvoid
80110370Sphkinit_TSC(void)
811390Ssos{
82110370Sphk	u_int64_t tscval[2];
831390Ssos
8432054Sphk	if (cpu_feature & CPUID_TSC)
8532054Sphk		tsc_present = 1;
8632054Sphk	else
8732054Sphk		tsc_present = 0;
8832054Sphk
89110370Sphk	if (!tsc_present)
90110370Sphk		return;
9115508Sbde
92110370Sphk	if (bootverbose)
93110370Sphk	        printf("Calibrating TSC clock ... ");
9415508Sbde
95110370Sphk	tscval[0] = rdtsc();
96110370Sphk	DELAY(1000000);
97110370Sphk	tscval[1] = rdtsc();
9815508Sbde
99110370Sphk	tsc_freq = tscval[1] - tscval[0];
100110370Sphk	if (bootverbose)
101110370Sphk		printf("TSC clock: %ju Hz\n", (intmax_t)tsc_freq);
10215508Sbde
103110370Sphk#if defined(SMP)
10434617Sphk	/*
10534617Sphk	 * We can not use the TSC in SMP mode, until we figure out a
10634617Sphk	 * cheap (impossible), reliable and precise (yeah right!)  way
10734617Sphk	 * to synchronize the TSCs of all the CPUs.
108110370Sphk	 * Modern SMP hardware has the ACPI timer and we use that.
10934617Sphk	 */
110110370Sphk	return;
111110370Sphk#endif
11234617Sphk
11334617Sphk	/*
11449186Smsmith	 * We can not use the TSC if we support APM. Precise timekeeping
11549186Smsmith	 * on an APM'ed machine is at best a fools pursuit, since
11634617Sphk	 * any and all of the time spent in various SMM code can't
11734617Sphk	 * be reliably accounted for.  Reading the RTC is your only
11834617Sphk	 * source of reliable time info.  The i8254 looses too of course
11934617Sphk	 * but we need to have some kind of time...
12049186Smsmith	 * We don't know at this point whether APM is going to be used
12149186Smsmith	 * or not, nor when it might be activated.  Play it safe.
12234617Sphk	 */
12385835Siwasaki	if (power_pm_get_type() == POWER_PM_TYPE_APM) {
12485835Siwasaki		if (bootverbose)
125110370Sphk			printf("TSC timecounter disabled: APM enabled.\n");
12664031Sphk		return;
12764031Sphk	}
12834617Sphk
12947592Sphk	if (tsc_present && tsc_freq != 0 && !tsc_is_broken) {
13040610Sphk		tsc_timecounter.tc_frequency = tsc_freq;
13158377Sphk		tc_init(&tsc_timecounter);
13233690Sphk	}
13334617Sphk
1342913Sache	return;
1354Srgrimes}
1364Srgrimes
13715508Sbdestatic int
13862573Sphksysctl_machdep_tsc_freq(SYSCTL_HANDLER_ARGS)
13915508Sbde{
14015508Sbde	int error;
141110039Sphk	uint64_t freq;
14215508Sbde
14348888Sbde	if (tsc_timecounter.tc_frequency == 0)
14415508Sbde		return (EOPNOTSUPP);
14532005Sphk	freq = tsc_freq;
14648888Sbde	error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
14733690Sphk	if (error == 0 && req->newptr != NULL) {
14833690Sphk		tsc_freq = freq;
14940610Sphk		tsc_timecounter.tc_frequency = tsc_freq;
15033690Sphk	}
15115508Sbde	return (error);
15215508Sbde}
15315508Sbde
154110039SphkSYSCTL_PROC(_machdep, OID_AUTO, tsc_freq, CTLTYPE_QUAD | CTLFLAG_RW,
15598618Smp    0, sizeof(u_int), sysctl_machdep_tsc_freq, "IU", "");
15633690Sphk
15736441Sphkstatic unsigned
15836719Sphktsc_get_timecount(struct timecounter *tc)
15933690Sphk{
16036198Sphk	return (rdtsc());
16133690Sphk}
162