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